diff options
Diffstat (limited to 'src/pal/src/thread/process.cpp')
-rw-r--r-- | src/pal/src/thread/process.cpp | 211 |
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; |