Implement the createdump policy options and env variables (dotnet/coreclr#11032)
authorMike McLaughlin <mikem@microsoft.com>
Tue, 18 Apr 2017 23:54:53 +0000 (16:54 -0700)
committerGitHub <noreply@github.com>
Tue, 18 Apr 2017 23:54:53 +0000 (16:54 -0700)
Added these command line options:

-f, --name - dump path and file name. The pid can be placed in the name with %d. The default is "/tmp/coredump.%d"
-n, --normal - create minidump (default).
-h, --withheap - create minidump with heap.
-m, --micro - create triage minidump.
-d, --diag - enable diagnostic messages.

Added these environment variables:

COMPlus_DbgMiniDumpType - if set to "1" generate MiniDumpNormal, "2" MiniDumpWithPrivateReadWriteMemory, "3" MiniDumpFilterTriage. Default is MiniDumpNormal.
COMPlus_DbgMiniDumpName - if set, use as the template to create the dump path and file name. The pid can be placed in the name with %d. The default is "/tmp/coredump.%d".

Commit migrated from https://github.com/dotnet/coreclr/commit/29e59e81de5489a3c0515b5d1d50baeb06269bd1

src/coreclr/src/debug/createdump/crashinfo.cpp
src/coreclr/src/debug/createdump/crashinfo.h
src/coreclr/src/debug/createdump/createdump.cpp
src/coreclr/src/debug/createdump/dumpwriter.cpp
src/coreclr/src/pal/src/thread/process.cpp

index 8f72542..f92630b 100644 (file)
@@ -120,6 +120,8 @@ CrashInfo::EnumerateAndSuspendThreads()
             else 
             {
                 fprintf(stderr, "ptrace(ATTACH, %d) FAILED %s\n", tid, strerror(errno));
+                closedir(taskDir);
+                return false;
             }
         }
     }
@@ -129,7 +131,7 @@ CrashInfo::EnumerateAndSuspendThreads()
 }
 
 bool
-CrashInfo::GatherCrashInfo(const char* pszExePath, MINIDUMP_TYPE minidumpType)
+CrashInfo::GatherCrashInfo(const char* programPath, MINIDUMP_TYPE minidumpType)
 {
     // Get the process info
     if (!GetStatus(m_pid, &m_ppid, &m_tgid, &m_name))
@@ -160,7 +162,7 @@ CrashInfo::GatherCrashInfo(const char* pszExePath, MINIDUMP_TYPE minidumpType)
         return false;
     }
     // Gather all the useful memory regions from the DAC
-    if (!EnumerateMemoryRegionsWithDAC(pszExePath, minidumpType))
+    if (!EnumerateMemoryRegionsWithDAC(programPath, minidumpType))
     {
         return false;
     }
@@ -326,7 +328,7 @@ CrashInfo::EnumerateModuleMappings()
 }
 
 bool
-CrashInfo::EnumerateMemoryRegionsWithDAC(const char *pszExePath, MINIDUMP_TYPE minidumpType)
+CrashInfo::EnumerateMemoryRegionsWithDAC(const char* programPath, MINIDUMP_TYPE minidumpType)
 {
     PFN_CLRDataCreateInstance pfnCLRDataCreateInstance = nullptr;
     ICLRDataEnumMemoryRegions *clrDataEnumRegions = nullptr;
@@ -336,7 +338,7 @@ CrashInfo::EnumerateMemoryRegionsWithDAC(const char *pszExePath, MINIDUMP_TYPE m
 
     // We assume that the DAC is in the same location as this createdump exe
     ArrayHolder<char> dacPath = new char[MAX_LONGPATH];
-    strcpy_s(dacPath, MAX_LONGPATH, pszExePath);
+    strcpy_s(dacPath, MAX_LONGPATH, programPath);
     char *last = strrchr(dacPath, '/');
     if (last != nullptr)
     {
@@ -572,13 +574,10 @@ CrashInfo::CombineMemoryRegions()
     if (g_diagnostics)
     {
         TRACE("Memory Regions:\n");
-        uint64_t total = 0;
         for (const MemoryRegion& region : m_memoryRegions)
         {
             region.Print();
-            total += region.Size();
         }
-        TRACE("Total %ld bytes (%ld pages) to write\n", total, total >> PAGE_SHIFT);
     }
 }
 
index a03ebe3..bdd19cf 100644 (file)
@@ -34,7 +34,7 @@ public:
     CrashInfo(pid_t pid, DataTarget& dataTarget);
     virtual ~CrashInfo();
     bool EnumerateAndSuspendThreads();
-    bool GatherCrashInfo(const char* pszExePath, MINIDUMP_TYPE minidumpType);
+    bool GatherCrashInfo(const char* programPath, MINIDUMP_TYPE minidumpType);
     void ResumeThreads();
     static bool GetStatus(pid_t pid, pid_t* ppid, pid_t* tgid, char** name);
 
@@ -63,7 +63,7 @@ public:
 private:
     bool GetAuxvEntries();
     bool EnumerateModuleMappings();
-    bool EnumerateMemoryRegionsWithDAC(const char* pszExePath, MINIDUMP_TYPE minidumpType);
+    bool EnumerateMemoryRegionsWithDAC(const char* programPath, MINIDUMP_TYPE minidumpType);
     bool GetDSOInfo();
     bool ReadMemory(void* address, void* buffer, size_t size);
     void InsertMemoryRegion(uint64_t address, size_t size);
index 4f43d11..ccc284b 100644 (file)
@@ -4,18 +4,26 @@
 
 #include "createdump.h"
 
+const char* g_help = "createdump [options] pid\n" 
+"-f, --name - dump path and file name. The pid can be placed in the name with %d. The default is '/tmp/coredump.%d'\n"
+"-n, --normal - create minidump (default).\n"
+"-h, --withheap - create minidump with heap.\n" 
+"-m, --micro - create triage minidump.\n" 
+"-d, --diag - enable diagnostic messages.\n";
+
 bool g_diagnostics = true;
 
 //
 // Create a minidump using the DAC's enum memory regions interface
 //
 static bool 
-CreateDump(const char* pszExePath, const char* dumpPathTemplate, pid_t pid, MINIDUMP_TYPE minidumpType)
+CreateDump(const char* programPath, const char* dumpPathTemplate, pid_t pid, MINIDUMP_TYPE minidumpType)
 {
     DataTarget* dataTarget = new DataTarget(pid);
     CrashInfo* crashInfo = new CrashInfo(pid, *dataTarget);
     DumpWriter* dumpWriter = new DumpWriter(*dataTarget, *crashInfo);
     ArrayHolder<char> dumpPath = new char[MAX_LONGPATH];
+    const char* dumpType = "minidump";
     bool result = false;
 
     // Suspend all the threads in the target process and build the list of threads
@@ -29,7 +37,7 @@ CreateDump(const char* pszExePath, const char* dumpPathTemplate, pid_t pid, MINI
         goto exit;
     }
     // Gather all the info about the process, threads (registers, etc.) and memory regions
-    if (!crashInfo->GatherCrashInfo(pszExePath, minidumpType))
+    if (!crashInfo->GatherCrashInfo(programPath, minidumpType))
     {
         goto exit;
     }
@@ -38,6 +46,20 @@ CreateDump(const char* pszExePath, const char* dumpPathTemplate, pid_t pid, MINI
     {
         goto exit;
     }
+    switch (minidumpType)
+    {
+        case MiniDumpWithPrivateReadWriteMemory:
+            dumpType = "minidump with heap";
+            break;
+
+        case MiniDumpFilterTriage:
+            dumpType = "triage minidump";
+            break;
+
+        default:
+            break;
+    }
+    printf("Writing %s to file %s\n", dumpType, (char*)dumpPath);
     if (!dumpWriter->WriteDump())
     {
         goto exit;
@@ -56,7 +78,10 @@ exit:
 //
 int __cdecl main(const int argc, const char* argv[])
 {
+    MINIDUMP_TYPE minidumpType = MiniDumpNormal;
     const char* dumpPathTemplate = "/tmp/coredump.%d";
+    const char* programPath = nullptr;
+    pid_t pid = 0;
 
     char* diagnostics = getenv("COMPlus_CreateDumpDiagnostics");
     g_diagnostics = diagnostics != nullptr && strcmp(diagnostics, "1") == 0;
@@ -64,24 +89,52 @@ int __cdecl main(const int argc, const char* argv[])
     int exitCode = PAL_InitializeDLL();
     if (exitCode != 0)
     {
-        fprintf(stderr, "PAL_Initialize FAILED %d\n", exitCode);
+        fprintf(stderr, "PAL initialization FAILED %d\n", exitCode);
         return exitCode;
     }
-    pid_t pid;
-    if (argc < 2)
+    programPath = *argv;
+    argv++;
+
+    for (int i = 1; i < argc; i++)
+    {
+        if (*argv != nullptr)
+        {
+            if ((strcmp(*argv, "-f") == 0) || (strcmp(*argv, "--name") == 0))
+            {
+                dumpPathTemplate = *++argv;
+            }
+            else if ((strcmp(*argv, "-n") == 0) || (strcmp(*argv, "--normal") == 0))
+            {
+                minidumpType = MiniDumpNormal;
+            }
+            else if ((strcmp(*argv, "-h") == 0) || (strcmp(*argv, "--withheap") == 0))
+            {
+                minidumpType = MiniDumpWithPrivateReadWriteMemory;
+            }
+            else if ((strcmp(*argv, "-m") == 0) || (strcmp(*argv, "--micro") == 0))
+            {
+                minidumpType = MiniDumpFilterTriage;
+            }
+            else if ((strcmp(*argv, "-d") == 0) || (strcmp(*argv, "--diag") == 0))
+            {
+                g_diagnostics = true;
+            }
+            else {
+                pid = atoll(*argv);
+            }
+            argv++;
+        }
+    }
+    // if no pid or invalid command line option
+    if (pid == 0)
     {
-        fprintf(stderr, "Not enough arguments\n");
+        fprintf(stderr, "%s", g_help);
         exitCode = -1;
-        goto exit;
     }
-    pid = _atoi64(argv[1]);
-
-    if (!CreateDump(argv[0], dumpPathTemplate, pid, MiniDumpNormal)) 
+    else if (!CreateDump(programPath, dumpPathTemplate, pid, minidumpType)) 
     {
         exitCode = -1;
-        goto exit;
     }
-exit:
     PAL_TerminateEx(exitCode);
     return exitCode;
 }
index ef3adac..cec19e8 100644 (file)
@@ -70,7 +70,6 @@ DumpWriter::OpenDump(char* dumpFileName)
         fprintf(stderr, "Could not open output %s: %s\n", dumpFileName, strerror(errno));
         return false;
     }
-    printf("Writing core file %s\n", dumpFileName);
     return true;
 }
 
@@ -175,7 +174,7 @@ DumpWriter::WriteDump()
     }
     offset += finalNoteAlignment;
 
-    printf("Writing memory region headers to core file\n");
+    TRACE("Writing memory region headers to core file\n");
 
     // Write memory region note headers
     for (const MemoryRegion& memoryRegion : m_crashInfo.MemoryRegions())
@@ -208,7 +207,7 @@ DumpWriter::WriteDump()
         return false;
     }
 
-    printf("Writing %ld thread entries to core file\n", m_crashInfo.Threads().size());
+    TRACE("Writing %ld thread entries to core file\n", m_crashInfo.Threads().size());
 
     // Write all the thread's state and registers
     for (const ThreadInfo* thread : m_crashInfo.Threads()) 
@@ -228,13 +227,15 @@ DumpWriter::WriteDump()
         }
     }
 
-    printf("Writing %ld memory regions to core file\n", m_crashInfo.MemoryRegions().size());
+    TRACE("Writing %ld memory regions to core file\n", m_crashInfo.MemoryRegions().size());
 
     // Read from target process and write memory regions to core
+    uint64_t total = 0;
     for (const MemoryRegion& memoryRegion : m_crashInfo.MemoryRegions())
     {
         uint32_t size = memoryRegion.Size();
         uint64_t address = memoryRegion.StartAddress();
+        total += size;
 
         while (size > 0)
         {
@@ -255,6 +256,8 @@ DumpWriter::WriteDump()
         }
     }
 
+    printf("Written %ld bytes (%ld pages) to core file\n", total, total >> PAGE_SHIFT);
+
     return true;
 }
 
@@ -275,7 +278,7 @@ DumpWriter::WriteProcessInfo()
     nhdr.n_descsz = sizeof(prpsinfo_t);
     nhdr.n_type = NT_PRPSINFO;
 
-    printf("Writing process information to core file\n");
+    TRACE("Writing process information to core file\n");
 
     // Write process info data to core file
     if (!WriteData(&nhdr, sizeof(nhdr)) ||
@@ -295,7 +298,7 @@ DumpWriter::WriteAuxv()
     nhdr.n_descsz = m_crashInfo.GetAuxvSize();
     nhdr.n_type = NT_AUXV;
 
-    printf("Writing %ld auxv entries to core file\n", m_crashInfo.AuxvEntries().size());
+    TRACE("Writing %ld auxv entries to core file\n", m_crashInfo.AuxvEntries().size());
 
     if (!WriteData(&nhdr, sizeof(nhdr)) ||
         !WriteData("CORE\0AUX", 8)) { 
@@ -373,7 +376,7 @@ DumpWriter::WriteNTFileInfo()
     size_t count = m_crashInfo.ModuleMappings().size();
     size_t pageSize = PAGE_SIZE;
 
-    printf("Writing %ld NT_FILE entries to core file\n", m_crashInfo.ModuleMappings().size());
+    TRACE("Writing %ld NT_FILE entries to core file\n", m_crashInfo.ModuleMappings().size());
 
     if (!WriteData(&nhdr, sizeof(nhdr)) ||
         !WriteData("CORE\0FIL", 8) ||
index e7380ee..e7a2d2f 100644 (file)
@@ -149,7 +149,7 @@ DWORD gSID = (DWORD) -1;
 Volatile<PSHUTDOWN_CALLBACK> g_shutdownCallback = nullptr;
 
 // Crash dump generating program arguments. Initialized in PROCAbortInitialize().
-char *g_argvCreateDump[3] = { nullptr, nullptr, nullptr };
+char* g_argvCreateDump[8] = { nullptr };
 
 //
 // Key used for associating CPalThread's with the underlying pthread
@@ -2895,8 +2895,11 @@ PROCAbortInitialize()
         }
         const char* DumpGeneratorName = "createdump";
         int programLen = strlen(g_szCoreCLRPath) + strlen(DumpGeneratorName);
-        char* program = new char[programLen];
-
+        char* program = (char*)InternalMalloc(programLen);
+        if (program == nullptr)
+        {
+            return FALSE;
+        }
         if (strcpy_s(program, programLen, g_szCoreCLRPath) != SAFECRT_SUCCESS)
         {
             return FALSE;
@@ -2914,19 +2917,50 @@ PROCAbortInitialize()
         {
             return FALSE;
         }
-        char pidarg[128];
-        if (sprintf_s(pidarg, sizeof(pidarg), "%d", gPID) == -1)
+        char* pidarg = (char*)InternalMalloc(128);
+        if (pidarg == nullptr)
         {
             return FALSE;
         }
-        g_argvCreateDump[0] = program;
-        g_argvCreateDump[1] = _strdup(pidarg);
-        g_argvCreateDump[2] = nullptr;
-
-        if (g_argvCreateDump[0] == nullptr || g_argvCreateDump[1] == nullptr)
+        if (sprintf_s(pidarg, 128, "%d", gPID) == -1)
         {
             return FALSE;
         }
+        const char** argv = (const char**)g_argvCreateDump;
+        *argv++ = program;
+
+        char* envvar = getenv("COMPlus_DbgMiniDumpName");
+        if (envvar != nullptr)
+        {
+            *argv++ = "--name";
+            *argv++ = envvar;
+        }
+
+        envvar = getenv("COMPlus_DbgMiniDumpType");
+        if (envvar != nullptr)
+        {
+            if (strcmp(envvar, "1") == 0)
+            {
+                *argv++ = "--normal";
+            }
+            else if (strcmp(envvar, "2") == 0)
+            {
+                *argv++ = "--withheap";
+            }
+            else if (strcmp(envvar, "3") == 0)
+            {
+                *argv++ = "--micro";
+            }
+        }
+
+        envvar = getenv("COMPlus_CreateDumpDiagnostics");
+        if (envvar != nullptr && strcmp(envvar, "1") == 0)
+        {
+            *argv++ = "--diag";
+        }
+
+        *argv++ = pidarg;
+        *argv = nullptr;
     }
     return TRUE;
 }