Add generate crash dump command to diagnostics server (#24460)
[platform/upstream/coreclr.git] / src / pal / src / thread / process.cpp
index 445b75c..8b9fec4 100644 (file)
@@ -3206,119 +3206,107 @@ PROCNotifyProcessShutdown()
 
 /*++
 Function
-  PROCAbortInitialize()
+  PROCBuildCreateDumpCommandLine
 
 Abstract
-  Initialize the process abort crash dump program file path and
-  name. Doing all of this ahead of time so nothing is allocated
-  or copied in PROCAbort/signal handler.
+  Builds the createdump command line from the arguments.
 
 Return
   TRUE - succeeds, FALSE - fails
 
 --*/
 BOOL
-PROCAbortInitialize()
+PROCBuildCreateDumpCommandLine(const char** argv, char* dumpName, char* dumpType, BOOL diag)
 {
-    char* enabled = getenv("COMPlus_DbgEnableMiniDump");
-    if (enabled != nullptr && _stricmp(enabled, "1") == 0)
+    if (g_szCoreCLRPath == nullptr)
     {
-        if (g_szCoreCLRPath == nullptr)
-        {
-            return FALSE;
-        }
-        const char* DumpGeneratorName = "createdump";
-        int programLen = strlen(g_szCoreCLRPath) + strlen(DumpGeneratorName) + 1;
-        char* program = (char*)InternalMalloc(programLen);
-        if (program == nullptr)
-        {
-            return FALSE;
-        }
-        if (strcpy_s(program, programLen, g_szCoreCLRPath) != SAFECRT_SUCCESS)
-        {
-            return FALSE;
-        }
-        char *last = strrchr(program, '/');
-        if (last != nullptr)
-        {
-            *(last + 1) = '\0';
-        }
-        else
-        {
-            program[0] = '\0';
-        }
-        if (strcat_s(program, programLen, DumpGeneratorName) != SAFECRT_SUCCESS)
+        return FALSE;
+    }
+    const char* DumpGeneratorName = "createdump";
+    int programLen = strlen(g_szCoreCLRPath) + strlen(DumpGeneratorName) + 1;
+    char* program = (char*)InternalMalloc(programLen);
+    if (program == nullptr)
+    {
+        return FALSE;
+    }
+    if (strcpy_s(program, programLen, g_szCoreCLRPath) != SAFECRT_SUCCESS)
+    {
+        return FALSE;
+    }
+    char *last = strrchr(program, '/');
+    if (last != nullptr)
+    {
+        *(last + 1) = '\0';
+    }
+    else
+    {
+        program[0] = '\0';
+    }
+    if (strcat_s(program, programLen, DumpGeneratorName) != SAFECRT_SUCCESS)
+    {
+        return FALSE;
+    }
+    char* pidarg = (char*)InternalMalloc(128);
+    if (pidarg == nullptr)
+    {
+        return FALSE;
+    }
+    if (sprintf_s(pidarg, 128, "%d", gPID) == -1)
+    {
+        return FALSE;
+    }
+    *argv++ = program;
+
+    if (dumpName != nullptr)
+    {
+        *argv++ = "--name";
+        *argv++ = dumpName;
+    }
+
+    if (dumpType != nullptr)
+    {
+        if (strcmp(dumpType, "1") == 0)
         {
-            return FALSE;
+            *argv++ = "--normal";
         }
-        char* pidarg = (char*)InternalMalloc(128);
-        if (pidarg == nullptr)
+        else if (strcmp(dumpType, "2") == 0)
         {
-            return FALSE;
+            *argv++ = "--withheap";
         }
-        if (sprintf_s(pidarg, 128, "%d", gPID) == -1)
+        else if (strcmp(dumpType, "3") == 0)
         {
-            return FALSE;
+            *argv++ = "--triage";
         }
-        const char** argv = (const char**)g_argvCreateDump;
-        *argv++ = program;
-
-        char* envvar = getenv("COMPlus_DbgMiniDumpName");
-        if (envvar != nullptr)
+        else if (strcmp(dumpType, "4") == 0)
         {
-            *argv++ = "--name";
-            *argv++ = envvar;
+            *argv++ = "--full";
         }
+    }
 
-        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++ = "--triage";
-            }
-            else if (strcmp(envvar, "4") == 0)
-            {
-                *argv++ = "--full";
-            }
-        }
+    if (diag)
+    {
+        *argv++ = "--diag";
+    }
 
-        envvar = getenv("COMPlus_CreateDumpDiagnostics");
-        if (envvar != nullptr && strcmp(envvar, "1") == 0)
-        {
-            *argv++ = "--diag";
-        }
+    *argv++ = pidarg;
+    *argv = nullptr;
 
-        *argv++ = pidarg;
-        *argv = nullptr;
-    }
     return TRUE;
 }
 
 /*++
 Function:
-  PROCCreateCrashDumpIfEnabled
+  PROCCreateCrashDump
 
-  Creates crash dump of the process (if enabled). Can be
-  called from the unhandled native exception handler.
+  Creates crash dump of the process. Can be called from the 
+  unhandled native exception handler.
 
 (no return value)
 --*/
-VOID
-PROCCreateCrashDumpIfEnabled()
+BOOL
+PROCCreateCrashDump(char** argv)
 {
 #if HAVE_PRCTL_H && HAVE_PR_SET_PTRACER
-    // If enabled, launch the create minidump utility and wait until it completes
-    if (g_argvCreateDump[0] == nullptr)
-        return;
 
     // Fork the core dump child process.
     pid_t childpid = fork();
@@ -3326,14 +3314,16 @@ PROCCreateCrashDumpIfEnabled()
     // If error, write an error to trace log and abort
     if (childpid == -1)
     {
-        ERROR("PROCAbort: fork() FAILED %d (%s)\n", errno, strerror(errno));
+        ERROR("PROCCreateCrashDump: fork() FAILED %d (%s)\n", errno, strerror(errno));
+        return false;
     }
     else if (childpid == 0)
     {
         // Child process
-        if (execve(g_argvCreateDump[0], g_argvCreateDump, palEnvironment) == -1)
+        if (execve(argv[0], argv, palEnvironment) == -1)
         {
-            ERROR("PROCAbort: execve FAILED %d (%s)\n", errno, strerror(errno));
+            ERROR("PPROCCreateCrashDump: execve FAILED %d (%s)\n", errno, strerror(errno));
+            return false;
         }
     }
     else
@@ -3341,18 +3331,122 @@ PROCCreateCrashDumpIfEnabled()
         // Gives the child process permission to use /proc/<pid>/mem and ptrace
         if (prctl(PR_SET_PTRACER, childpid, 0, 0, 0) == -1)
         {
-            ERROR("PROCAbort: prctl() FAILED %d (%s)\n", errno, strerror(errno));
+            ERROR("PPROCCreateCrashDump: prctl() FAILED %d (%s)\n", errno, strerror(errno));
+            return false;
         }
         // Parent waits until the child process is done
-        int wstatus;
+        int wstatus = 0;
         int result = waitpid(childpid, &wstatus, 0);
         if (result != childpid)
         {
-            ERROR("PROCAbort: waitpid FAILED result %d wstatus %d errno %d (%s)\n",
+            ERROR("PPROCCreateCrashDump: waitpid FAILED result %d wstatus %d errno %d (%s)\n",
                 result, wstatus, errno, strerror(errno));
+            return false;
         }
+        return !WIFEXITED(wstatus) || WEXITSTATUS(wstatus) == 0;
     }
 #endif // HAVE_PRCTL_H && HAVE_PR_SET_PTRACER
+    return true;
+}
+
+/*++
+Function
+  PROCAbortInitialize()
+
+Abstract
+  Initialize the process abort crash dump program file path and
+  name. Doing all of this ahead of time so nothing is allocated
+  or copied in PROCAbort/signal handler.
+
+Return
+  TRUE - succeeds, FALSE - fails
+
+--*/
+BOOL
+PROCAbortInitialize()
+{
+    char* enabled = getenv("COMPlus_DbgEnableMiniDump");
+    if (enabled != nullptr && _stricmp(enabled, "1") == 0)
+    {
+        char* dumpName = getenv("COMPlus_DbgMiniDumpName");
+        char* dumpType = getenv("COMPlus_DbgMiniDumpType");
+        char* diagStr = getenv("COMPlus_CreateDumpDiagnostics");
+        BOOL diag = diagStr != nullptr && strcmp(diagStr, "1") == 0;
+
+        if (!PROCBuildCreateDumpCommandLine((const char **)g_argvCreateDump, dumpName, dumpType, diag))
+        {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+/*++
+Function:
+  PAL_GenerateCoreDump
+
+Abstract:
+  Public entry point to create a crash dump of the process.
+
+Parameters:
+    dumpName
+    dumpType:
+        Normal = 1,
+        WithHeap = 2,
+        Triage = 3,
+        Full = 4
+    diag
+        true - log createdump diagnostics to console
+
+Return:
+    TRUE success
+    FALSE failed
+--*/
+BOOL
+PAL_GenerateCoreDump(
+    LPCSTR dumpName, 
+    INT dumpType, 
+    BOOL diag)
+{
+    char* argvCreateDump[8] = { nullptr };
+    char dumpTypeStr[16];
+
+    if (dumpType < 1 || dumpType > 4)
+    {
+        return FALSE;
+    }
+    if (dumpName != nullptr && dumpName[0] == '\0')
+    {
+        dumpName = nullptr;
+    }
+    if (_itoa_s(dumpType, dumpTypeStr, sizeof(dumpTypeStr), 10) != 0)
+    {
+        return FALSE;
+    }
+    if (!PROCBuildCreateDumpCommandLine((const char **)argvCreateDump, (char*)dumpName, dumpTypeStr, diag))
+    {
+        return FALSE;
+    }
+    return PROCCreateCrashDump(argvCreateDump);
+}
+
+/*++
+Function:
+  PROCCreateCrashDumpIfEnabled
+
+  Creates crash dump of the process (if enabled). Can be
+  called from the unhandled native exception handler.
+
+(no return value)
+--*/
+VOID
+PROCCreateCrashDumpIfEnabled()
+{
+    // If enabled, launch the create minidump utility and wait until it completes
+    if (g_argvCreateDump[0] != nullptr)
+    {
+        PROCCreateCrashDump(g_argvCreateDump);
+    }
 }
 
 /*++