summaryrefslogtreecommitdiff
path: root/src/pal/src/thread/process.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/pal/src/thread/process.cpp')
-rw-r--r--src/pal/src/thread/process.cpp211
1 files changed, 179 insertions, 32 deletions
diff --git a/src/pal/src/thread/process.cpp b/src/pal/src/thread/process.cpp
index 050665ce7c..2a93d3c57d 100644
--- a/src/pal/src/thread/process.cpp
+++ b/src/pal/src/thread/process.cpp
@@ -49,12 +49,17 @@ SET_DEFAULT_DEBUG_CHANNEL(PROCESS); // some headers have code with asserts, so d
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
+#if HAVE_PRCTL_H
+#include <sys/prctl.h>
+#include <sys/syscall.h>
+#endif
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <debugmacrosext.h>
#include <semaphore.h>
#include <stdint.h>
+#include <dlfcn.h>
#ifdef __APPLE__
#include <sys/sysctl.h>
@@ -67,6 +72,8 @@ SET_DEFAULT_DEBUG_CHANNEL(PROCESS); // some headers have code with asserts, so d
#include <kvm.h>
#endif
+extern char *g_szCoreCLRPath;
+
using namespace CorUnix;
CObjectType CorUnix::otProcess(
@@ -87,18 +94,6 @@ CObjectType CorUnix::otProcess(
CObjectType::NoOwner
);
-static
-DWORD
-PALAPI
-StartupHelperThread(
- LPVOID p);
-
-static
-BOOL
-GetProcessIdDisambiguationKey(
- IN DWORD processId,
- OUT UINT64 *disambiguationKey);
-
//
// Helper memory page used by the FlushProcessWriteBuffers
//
@@ -153,6 +148,9 @@ DWORD gSID = (DWORD) -1;
// Function to call during PAL/process shutdown/abort
Volatile<PSHUTDOWN_CALLBACK> g_shutdownCallback = nullptr;
+// Crash dump generating program arguments. Initialized in PROCAbortInitialize().
+char* g_argvCreateDump[8] = { nullptr };
+
//
// Key used for associating CPalThread's with the underlying pthread
// (through pthread_setspecific)
@@ -172,22 +170,30 @@ enum FILETYPE
FILE_DIR /*Directory*/
};
+static
+DWORD
+PALAPI
+StartupHelperThread(
+ LPVOID p);
+
+static
+BOOL
+GetProcessIdDisambiguationKey(
+ IN DWORD processId,
+ OUT UINT64 *disambiguationKey);
+
PAL_ERROR
PROCGetProcessStatus(
CPalThread *pThread,
HANDLE hProcess,
PROCESS_STATE *pps,
- DWORD *pdwExitCode
- );
+ DWORD *pdwExitCode);
-static BOOL getFileName(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
- PathCharString& lpFileName);
-static char ** buildArgv(LPCWSTR lpCommandLine, PathCharString& lpAppPath,
- UINT *pnArg, BOOL prependLoader);
+static BOOL getFileName(LPCWSTR lpApplicationName, LPWSTR lpCommandLine, PathCharString& lpFileName);
+static char ** buildArgv(LPCWSTR lpCommandLine, PathCharString& lpAppPath, UINT *pnArg, BOOL prependLoader);
static BOOL getPath(PathCharString& lpFileName, PathCharString& lpPathFileName);
static int checkFileType(LPCSTR lpFileName);
-static BOOL PROCEndProcess(HANDLE hProcess, UINT uExitCode,
- BOOL bTerminateUnconditionally);
+static BOOL PROCEndProcess(HANDLE hProcess, UINT uExitCode, BOOL bTerminateUnconditionally);
ProcessModules *GetProcessModulesFromHandle(IN HANDLE hProcess, OUT LPDWORD lpCount);
ProcessModules *CreateProcessModules(IN DWORD dwProcessId, OUT LPDWORD lpCount);
@@ -1382,7 +1388,7 @@ static BOOL PROCEndProcess(HANDLE hProcess, UINT uExitCode, BOOL bTerminateUncon
// (1) it doesn't run atexit handlers
// (2) can invoke CrashReporter or produce a coredump,
// which is appropriate for TerminateProcess calls
- abort();
+ PROCAbort();
}
else
{
@@ -2081,9 +2087,12 @@ GetProcessIdDisambiguationKey(DWORD processId, UINT64 *disambiguationKey)
Builds the transport pipe names from the process id.
--*/
-void
+VOID
PALAPI
-PAL_GetTransportPipeName(char *name, DWORD id, const char *suffix)
+PAL_GetTransportPipeName(
+ OUT char *name,
+ IN DWORD id,
+ IN const char *suffix)
{
UINT64 disambiguationKey = 0;
BOOL ret = GetProcessIdDisambiguationKey(id, &disambiguationKey);
@@ -2829,7 +2838,7 @@ Return
None
--*/
-void
+VOID
DestroyProcessModules(IN ProcessModules *listHead)
{
for (ProcessModules *entry = listHead; entry != NULL; )
@@ -2841,7 +2850,7 @@ DestroyProcessModules(IN ProcessModules *listHead)
}
/*++
-Function:
+Function
PROCNotifyProcessShutdown
Calls the abort handler to do any shutdown cleanup. Call be called
@@ -2850,7 +2859,8 @@ Function:
(no return value)
--*/
__attribute__((destructor))
-void PROCNotifyProcessShutdown()
+VOID
+PROCNotifyProcessShutdown()
{
// Call back into the coreclr to clean up the debugger transport pipes
PSHUTDOWN_CALLBACK callback = InterlockedExchangePointer(&g_shutdownCallback, NULL);
@@ -2861,6 +2871,101 @@ void PROCNotifyProcessShutdown()
}
/*++
+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)
+ {
+ 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;
+ }
+ char* pidarg = (char*)InternalMalloc(128);
+ if (pidarg == nullptr)
+ {
+ return FALSE;
+ }
+ 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++ = "--triage";
+ }
+ }
+
+ envvar = getenv("COMPlus_CreateDumpDiagnostics");
+ if (envvar != nullptr && strcmp(envvar, "1") == 0)
+ {
+ *argv++ = "--diag";
+ }
+
+ *argv++ = pidarg;
+ *argv = nullptr;
+ }
+ return TRUE;
+}
+
+/*++
Function:
PROCAbort()
@@ -2870,10 +2975,51 @@ Function:
Does not return
--*/
PAL_NORETURN
-void
+VOID
PROCAbort()
{
+ // Do any shutdown cleanup before aborting or creating a core dump
PROCNotifyProcessShutdown();
+
+#if HAVE_PRCTL_H
+ // If enabled, launch the create minidump utility and wait until it completes
+ if (g_argvCreateDump[0] != nullptr)
+ {
+ // 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));
+ }
+ else if (childpid == 0)
+ {
+ // Child process
+ if (execve(g_argvCreateDump[0], g_argvCreateDump, palEnvironment) == -1)
+ {
+ ERROR("PROCAbort: execve FAILED %d (%s)\n", errno, strerror(errno));
+ }
+ }
+ 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));
+ }
+ // Parent waits until the child process is done
+ int wstatus;
+ int result = waitpid(childpid, &wstatus, 0);
+ if (result != childpid)
+ {
+ ERROR("PROCAbort: waitpid FAILED result %d wstatus %d errno %d (%s)\n",
+ result, wstatus, errno, strerror(errno));
+ }
+ }
+ }
+#endif // HAVE_PRCTL_H
+ // Abort the process after waiting for the core dump to complete
abort();
}
@@ -2886,7 +3032,8 @@ Abstract
Return
TRUE if it succeeded, FALSE otherwise
--*/
-BOOL InitializeFlushProcessWriteBuffers()
+BOOL
+InitializeFlushProcessWriteBuffers()
{
// Verify that the s_helperPage is really aligned to the VIRTUAL_PAGE_SIZE
_ASSERTE((((SIZE_T)s_helperPage) & (VIRTUAL_PAGE_SIZE - 1)) == 0);
@@ -3273,7 +3420,7 @@ Parameter
pThread: Thread object
--*/
-void
+VOID
CorUnix::PROCAddThread(
CPalThread *pCurrentThread,
CPalThread *pTargetThread
@@ -3306,7 +3453,7 @@ Parameter
(no return value)
--*/
-void
+VOID
CorUnix::PROCRemoveThread(
CPalThread *pCurrentThread,
CPalThread *pTargetThread
@@ -3376,7 +3523,7 @@ Return
--*/
INT
CorUnix::PROCGetNumberOfThreads(
- void)
+ VOID)
{
return g_dwThreadCount;
}
@@ -3479,7 +3626,7 @@ Note:
This function is used in ExitThread and TerminateProcess
--*/
-void
+VOID
CorUnix::TerminateCurrentProcessNoExit(BOOL bTerminateUnconditionally)
{
BOOL locked;