/*++
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();
// 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
// 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);
+ }
}
/*++
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "common.h"
+#include "fastserializer.h"
+#include "diagnosticprotocolhelper.h"
+#include "diagnosticsipc.h"
+#include "diagnosticsprotocol.h"
+
+#ifdef FEATURE_PERFTRACING
+#ifdef FEATURE_PAL
+
+static void WriteStatus(uint64_t result, IpcStream* pStream)
+{
+ uint32_t nBytesWritten = 0;
+ bool fSuccess = pStream->Write(&result, sizeof(result), nBytesWritten);
+ if (fSuccess)
+ {
+ fSuccess = pStream->Flush();
+ }
+}
+
+void DiagnosticProtocolHelper::GenerateCoreDump(IpcStream* pStream)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_PREEMPTIVE;
+ PRECONDITION(pStream != nullptr);
+ }
+ CONTRACTL_END;
+
+ if (pStream == nullptr)
+ return;
+
+ HRESULT hr = S_OK;
+
+ // TODO: Read within a loop.
+ uint8_t buffer[IpcStreamReadBufferSize] { };
+ uint32_t nNumberOfBytesRead = 0;
+ bool fSuccess = pStream->Read(buffer, sizeof(buffer), nNumberOfBytesRead);
+ if (fSuccess)
+ {
+ // The protocol buffer is defined as:
+ // string - dumpName (array<char> where the last char must = 0) or (length = 0)
+ // int - dumpType
+ // int - diagnostics
+ // returns
+ // ulong - status
+ LPCSTR dumpName;
+ INT dumpType;
+ INT diagnostics;
+
+ uint8_t *pBufferCursor = buffer;
+ uint32_t bufferLen = nNumberOfBytesRead;
+
+ if (TryParseString(pBufferCursor, bufferLen, dumpName) &&
+ TryParse(pBufferCursor, bufferLen, dumpType) &&
+ TryParse(pBufferCursor, bufferLen, diagnostics))
+ {
+ if (!PAL_GenerateCoreDump(dumpName, dumpType, diagnostics))
+ {
+ hr = E_FAIL;
+ }
+ }
+ else
+ {
+ hr = E_INVALIDARG;
+ }
+ }
+ else
+ {
+ hr = E_UNEXPECTED;
+ }
+
+ WriteStatus(hr, pStream);
+ delete pStream;
+}
+
+#endif // FEATURE_PAL
+#endif // FEATURE_PERFTRACING