diff options
author | dotnet-bot <dotnet-bot@microsoft.com> | 2022-03-09 01:18:37 +0300 |
---|---|---|
committer | dotnet-bot <dotnet-bot@microsoft.com> | 2022-03-09 01:18:37 +0300 |
commit | ef034e703d270205e149e330cf5355b7dc913a4c (patch) | |
tree | b923c7116d46be217dd61256a5829a082f282231 | |
parent | a31025a0f875d1b7974ec86f4c6364c27b62d42d (diff) | |
parent | 3a14bd70a3d63649f711cb8ef196e8467bfa68de (diff) |
Merge in 'release/6.0' changes
-rw-r--r-- | src/coreclr/debug/createdump/crashinfo.cpp | 16 | ||||
-rw-r--r-- | src/coreclr/debug/createdump/crashinfomac.cpp | 6 | ||||
-rw-r--r-- | src/coreclr/debug/createdump/crashinfounix.cpp | 12 | ||||
-rw-r--r-- | src/coreclr/debug/createdump/crashreportwriter.cpp | 6 | ||||
-rw-r--r-- | src/coreclr/debug/createdump/createdump.h | 2 | ||||
-rw-r--r-- | src/coreclr/debug/createdump/createdumpunix.cpp | 8 | ||||
-rw-r--r-- | src/coreclr/debug/createdump/createdumpwindows.cpp | 10 | ||||
-rw-r--r-- | src/coreclr/debug/createdump/dumpname.cpp | 6 | ||||
-rw-r--r-- | src/coreclr/debug/createdump/dumpwriter.cpp | 4 | ||||
-rw-r--r-- | src/coreclr/debug/createdump/dumpwriterelf.cpp | 9 | ||||
-rw-r--r-- | src/coreclr/debug/createdump/dumpwritermacho.cpp | 8 | ||||
-rw-r--r-- | src/coreclr/debug/createdump/main.cpp | 34 | ||||
-rw-r--r-- | src/coreclr/debug/createdump/threadinfomac.cpp | 10 | ||||
-rw-r--r-- | src/coreclr/debug/createdump/threadinfounix.cpp | 8 | ||||
-rw-r--r-- | src/coreclr/pal/src/thread/process.cpp | 6 | ||||
-rw-r--r-- | src/coreclr/vm/threads.h | 8 | ||||
-rw-r--r-- | src/coreclr/vm/threadsuspend.cpp | 350 |
17 files changed, 288 insertions, 215 deletions
diff --git a/src/coreclr/debug/createdump/crashinfo.cpp b/src/coreclr/debug/createdump/crashinfo.cpp index 77910208726..d939592efe8 100644 --- a/src/coreclr/debug/createdump/crashinfo.cpp +++ b/src/coreclr/debug/createdump/crashinfo.cpp @@ -67,7 +67,7 @@ CrashInfo::~CrashInfo() kern_return_t result = ::mach_port_deallocate(mach_task_self(), m_task); if (result != KERN_SUCCESS) { - fprintf(stderr, "~CrashInfo: mach_port_deallocate FAILED %x %s\n", result, mach_error_string(result)); + printf_error("~CrashInfo: mach_port_deallocate FAILED %x %s\n", result, mach_error_string(result)); } } #endif @@ -241,25 +241,25 @@ CrashInfo::InitializeDAC() m_hdac = LoadLibraryA(dacPath.c_str()); if (m_hdac == nullptr) { - fprintf(stderr, "LoadLibraryA(%s) FAILED %d\n", dacPath.c_str(), GetLastError()); + printf_error("LoadLibraryA(%s) FAILED %d\n", dacPath.c_str(), GetLastError()); goto exit; } pfnCLRDataCreateInstance = (PFN_CLRDataCreateInstance)GetProcAddress(m_hdac, "CLRDataCreateInstance"); if (pfnCLRDataCreateInstance == nullptr) { - fprintf(stderr, "GetProcAddress(CLRDataCreateInstance) FAILED %d\n", GetLastError()); + printf_error("GetProcAddress(CLRDataCreateInstance) FAILED %d\n", GetLastError()); goto exit; } hr = pfnCLRDataCreateInstance(__uuidof(ICLRDataEnumMemoryRegions), dataTarget, (void**)&m_pClrDataEnumRegions); if (FAILED(hr)) { - fprintf(stderr, "CLRDataCreateInstance(ICLRDataEnumMemoryRegions) FAILED %08x\n", hr); + printf_error("CLRDataCreateInstance(ICLRDataEnumMemoryRegions) FAILED %08x\n", hr); goto exit; } hr = pfnCLRDataCreateInstance(__uuidof(IXCLRDataProcess), dataTarget, (void**)&m_pClrDataProcess); if (FAILED(hr)) { - fprintf(stderr, "CLRDataCreateInstance(IXCLRDataProcess) FAILED %08x\n", hr); + printf_error("CLRDataCreateInstance(IXCLRDataProcess) FAILED %08x\n", hr); goto exit; } } @@ -302,7 +302,7 @@ CrashInfo::EnumerateMemoryRegionsWithDAC(MINIDUMP_TYPE minidumpType) HRESULT hr = m_pClrDataEnumRegions->EnumMemoryRegions(this, minidumpType, CLRDATA_ENUM_MEM_DEFAULT); if (FAILED(hr)) { - fprintf(stderr, "EnumMemoryRegions FAILED %08x\n", hr); + printf_error("EnumMemoryRegions FAILED %08x\n", hr); return false; } TRACE("EnumerateMemoryRegionsWithDAC: Memory enumeration FINISHED\n"); @@ -324,7 +324,7 @@ CrashInfo::EnumerateManagedModules() TRACE("EnumerateManagedModules: Module enumeration STARTED\n"); if (FAILED(hr = m_pClrDataProcess->StartEnumModules(&enumModules))) { - fprintf(stderr, "StartEnumModules FAILED %08x\n", hr); + printf_error("StartEnumModules FAILED %08x\n", hr); return false; } @@ -775,6 +775,7 @@ CrashInfo::Trace(const char* format, ...) { va_list args; va_start(args, format); + fprintf(stdout, "[createdump] "); vfprintf(stdout, format, args); fflush(stdout); va_end(args); @@ -788,6 +789,7 @@ CrashInfo::TraceVerbose(const char* format, ...) { va_list args; va_start(args, format); + fprintf(stdout, "[createdump] "); vfprintf(stdout, format, args); fflush(stdout); va_end(args); diff --git a/src/coreclr/debug/createdump/crashinfomac.cpp b/src/coreclr/debug/createdump/crashinfomac.cpp index 3ada3bd767c..390316b963a 100644 --- a/src/coreclr/debug/createdump/crashinfomac.cpp +++ b/src/coreclr/debug/createdump/crashinfomac.cpp @@ -12,7 +12,7 @@ CrashInfo::Initialize() kern_return_t result = ::task_for_pid(mach_task_self(), m_pid, &m_task); if (result != KERN_SUCCESS) { - fprintf(stderr, "task_for_pid(%d) FAILED %x %s\n", m_pid, result, mach_error_string(result)); + printf_error("task_for_pid(%d) FAILED %x %s\n", m_pid, result, mach_error_string(result)); return false; } return true; @@ -37,14 +37,14 @@ CrashInfo::EnumerateAndSuspendThreads() kern_return_t result = ::task_suspend(Task()); if (result != KERN_SUCCESS) { - fprintf(stderr, "task_suspend(%d) FAILED %x %s\n", m_pid, result, mach_error_string(result)); + printf_error("task_suspend(%d) FAILED %x %s\n", m_pid, result, mach_error_string(result)); return false; } result = ::task_threads(Task(), &threadList, &threadCount); if (result != KERN_SUCCESS) { - fprintf(stderr, "task_threads(%d) FAILED %x %s\n", m_pid, result, mach_error_string(result)); + printf_error("task_threads(%d) FAILED %x %s\n", m_pid, result, mach_error_string(result)); return false; } diff --git a/src/coreclr/debug/createdump/crashinfounix.cpp b/src/coreclr/debug/createdump/crashinfounix.cpp index 2f9605554ad..5d7c0a947ea 100644 --- a/src/coreclr/debug/createdump/crashinfounix.cpp +++ b/src/coreclr/debug/createdump/crashinfounix.cpp @@ -14,7 +14,7 @@ CrashInfo::Initialize() m_fd = open(memPath, O_RDONLY); if (m_fd == -1) { - fprintf(stderr, "open(%s) FAILED %d (%s)\n", memPath, errno, strerror(errno)); + printf_error("open(%s) FAILED %d (%s)\n", memPath, errno, strerror(errno)); return false; } // Get the process info @@ -58,7 +58,7 @@ CrashInfo::EnumerateAndSuspendThreads() DIR* taskDir = opendir(taskPath); if (taskDir == nullptr) { - fprintf(stderr, "opendir(%s) FAILED %s\n", taskPath, strerror(errno)); + printf_error("opendir(%s) FAILED %s\n", taskPath, strerror(errno)); return false; } @@ -76,7 +76,7 @@ CrashInfo::EnumerateAndSuspendThreads() } else { - fprintf(stderr, "ptrace(ATTACH, %d) FAILED %s\n", tid, strerror(errno)); + printf_error("ptrace(ATTACH, %d) FAILED %s\n", tid, strerror(errno)); closedir(taskDir); return false; } @@ -102,7 +102,7 @@ CrashInfo::GetAuxvEntries() int fd = open(auxvPath, O_RDONLY, 0); if (fd == -1) { - fprintf(stderr, "open(%s) FAILED %s\n", auxvPath, strerror(errno)); + printf_error("open(%s) FAILED %s\n", auxvPath, strerror(errno)); return false; } bool result = false; @@ -159,7 +159,7 @@ CrashInfo::EnumerateModuleMappings() FILE* mapsFile = fopen(mapPath, "r"); if (mapsFile == nullptr) { - fprintf(stderr, "fopen(%s) FAILED %s\n", mapPath, strerror(errno)); + printf_error("fopen(%s) FAILED %s\n", mapPath, strerror(errno)); return false; } // linuxGateAddress is the beginning of the kernel's mapping of @@ -377,7 +377,7 @@ GetStatus(pid_t pid, pid_t* ppid, pid_t* tgid, std::string* name) FILE *statusFile = fopen(statusPath, "r"); if (statusFile == nullptr) { - fprintf(stderr, "GetStatus fopen(%s) FAILED\n", statusPath); + printf_error("GetStatus fopen(%s) FAILED\n", statusPath); return false; } diff --git a/src/coreclr/debug/createdump/crashreportwriter.cpp b/src/coreclr/debug/createdump/crashreportwriter.cpp index 4e9382f65f1..a82557f257e 100644 --- a/src/coreclr/debug/createdump/crashreportwriter.cpp +++ b/src/coreclr/debug/createdump/crashreportwriter.cpp @@ -33,7 +33,7 @@ CrashReportWriter::WriteCrashReport(const std::string& dumpFileName) { std::string crashReportFile(dumpFileName); crashReportFile.append(".crashreport.json"); - printf("Writing crash report to file %s\n", crashReportFile.c_str()); + printf_status("Writing crash report to file %s\n", crashReportFile.c_str()); try { if (!OpenWriter(crashReportFile.c_str())) { @@ -44,7 +44,7 @@ CrashReportWriter::WriteCrashReport(const std::string& dumpFileName) } catch (const std::exception& e) { - fprintf(stderr, "Writing the crash report file FAILED\n"); + printf_error("Writing the crash report file FAILED\n"); // Delete the partial json file on error remove(crashReportFile.c_str()); @@ -271,7 +271,7 @@ CrashReportWriter::OpenWriter(const char* fileName) m_fd = open(fileName, O_WRONLY|O_CREAT|O_TRUNC, S_IWUSR | S_IRUSR); if (m_fd == -1) { - fprintf(stderr, "Could not create json file %s: %d %s\n", fileName, errno, strerror(errno)); + printf_error("Could not create json file %s: %d %s\n", fileName, errno, strerror(errno)); return false; } Write("{\n"); diff --git a/src/coreclr/debug/createdump/createdump.h b/src/coreclr/debug/createdump/createdump.h index f588867c792..ffd47b68912 100644 --- a/src/coreclr/debug/createdump/createdump.h +++ b/src/coreclr/debug/createdump/createdump.h @@ -111,3 +111,5 @@ typedef int T_CONTEXT; bool FormatDumpName(std::string& name, const char* pattern, const char* exename, int pid); bool CreateDump(const char* dumpPathTemplate, int pid, const char* dumpType, MINIDUMP_TYPE minidumpType, bool crashReport, int crashThread, int signal); +extern void printf_status(const char* format, ...); +extern void printf_error(const char* format, ...); diff --git a/src/coreclr/debug/createdump/createdumpunix.cpp b/src/coreclr/debug/createdump/createdumpunix.cpp index 6107adc625e..5e6733a8838 100644 --- a/src/coreclr/debug/createdump/createdumpunix.cpp +++ b/src/coreclr/debug/createdump/createdumpunix.cpp @@ -19,11 +19,11 @@ CreateDump(const char* dumpPathTemplate, int pid, const char* dumpType, MINIDUMP { goto exit; } - printf("Gathering state for process %d %s\n", pid, crashInfo->Name().c_str()); + printf_status("Gathering state for process %d %s\n", pid, crashInfo->Name().c_str()); if (signal != 0 || crashThread != 0) { - printf("Crashing thread %08x signal %08x\n", crashThread, signal); + printf_status("Crashing thread %08x signal %08x\n", crashThread, signal); } // Suspend all the threads in the target process and build the list of threads @@ -52,7 +52,7 @@ CreateDump(const char* dumpPathTemplate, int pid, const char* dumpType, MINIDUMP { goto exit; } - fprintf(stdout, "Writing %s to file %s\n", dumpType, dumpPath.c_str()); + printf_status("Writing %s to file %s\n", dumpType, dumpPath.c_str()); // Write the actual dump file if (!dumpWriter.OpenDump(dumpPath.c_str())) @@ -61,7 +61,7 @@ CreateDump(const char* dumpPathTemplate, int pid, const char* dumpType, MINIDUMP } if (!dumpWriter.WriteDump()) { - fprintf(stderr, "Writing dump FAILED\n"); + printf_error( "Writing dump FAILED\n"); // Delete the partial dump file on error remove(dumpPath.c_str()); diff --git a/src/coreclr/debug/createdump/createdumpwindows.cpp b/src/coreclr/debug/createdump/createdumpwindows.cpp index 6d474d3475d..ebcd6fca755 100644 --- a/src/coreclr/debug/createdump/createdumpwindows.cpp +++ b/src/coreclr/debug/createdump/createdumpwindows.cpp @@ -20,24 +20,24 @@ CreateDump(const char* dumpPathTemplate, int pid, const char* dumpType, MINIDUMP hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); if (hProcess == NULL) { - fprintf(stderr, "Invalid process id '%d' error %d\n", pid, GetLastError()); + printf_error("Invalid process id '%d' error %d\n", pid, GetLastError()); goto exit; } if (GetModuleBaseNameA(hProcess, NULL, pszName, MAX_LONGPATH) <= 0) { - fprintf(stderr, "Get process name FAILED %d\n", GetLastError()); + printf_error("Get process name FAILED %d\n", GetLastError()); goto exit; } if (!FormatDumpName(dumpPath, dumpPathTemplate, pszName, pid)) { goto exit; } - printf("Writing %s to file %s\n", dumpType, dumpPath.c_str()); + printf_status("Writing %s to file %s\n", dumpType, dumpPath.c_str()); hFile = CreateFileA(dumpPath.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { - fprintf(stderr, "Invalid dump path '%s' error %d\n", dumpPath.c_str(), GetLastError()); + printf_error("Invalid dump path '%s' error %d\n", dumpPath.c_str(), GetLastError()); goto exit; } @@ -54,7 +54,7 @@ CreateDump(const char* dumpPathTemplate, int pid, const char* dumpType, MINIDUMP int err = GetLastError(); if (err != HRESULT_FROM_WIN32(ERROR_PARTIAL_COPY)) { - fprintf(stderr, "Write dump FAILED 0x%08x\n", err); + printf_error("Write dump FAILED 0x%08x\n", err); break; } } diff --git a/src/coreclr/debug/createdump/dumpname.cpp b/src/coreclr/debug/createdump/dumpname.cpp index 751997c6755..a09a98aebc9 100644 --- a/src/coreclr/debug/createdump/dumpname.cpp +++ b/src/coreclr/debug/createdump/dumpname.cpp @@ -37,7 +37,7 @@ FormatDumpName(std::string& name, const char* pattern, const char* exename, int const char* p = pattern; if (*p == '|') { - fprintf(stderr, "Pipe syntax in dump name not supported\n"); + printf_error("Pipe syntax in dump name not supported\n"); return false; } @@ -81,7 +81,7 @@ FormatDumpName(std::string& name, const char* pattern, const char* exename, int ArrayHolder<char> buffer = new char[MAX_LONGPATH + 1]; if (gethostname(buffer, MAX_LONGPATH) != 0) { - fprintf(stderr, "Could not get the host name for dump name: %d\n", + printf_error("Could not get the host name for dump name: %d\n", #ifdef HOST_WINDOWS WSAGetLastError()); #else @@ -114,7 +114,7 @@ FormatDumpName(std::string& name, const char* pattern, const char* exename, int // pid of dumped process case 'P': default: - fprintf(stderr, "Invalid dump name format char '%c'\n", *p); + printf_error("Invalid dump name format char '%c'\n", *p); return false; } } diff --git a/src/coreclr/debug/createdump/dumpwriter.cpp b/src/coreclr/debug/createdump/dumpwriter.cpp index 4aa46ac3681..5946c37d667 100644 --- a/src/coreclr/debug/createdump/dumpwriter.cpp +++ b/src/coreclr/debug/createdump/dumpwriter.cpp @@ -26,7 +26,7 @@ DumpWriter::OpenDump(const char* dumpFileName) m_fd = open(dumpFileName, O_WRONLY|O_CREAT|O_TRUNC, S_IWUSR | S_IRUSR); if (m_fd == -1) { - fprintf(stderr, "Could not open output %s: %d %s\n", dumpFileName, errno, strerror(errno)); + printf_error("Could not open output %s: %d %s\n", dumpFileName, errno, strerror(errno)); return false; } return true; @@ -46,7 +46,7 @@ DumpWriter::WriteData(int fd, const void* buffer, size_t length) } while (written == -1 && errno == EINTR); if (written < 1) { - fprintf(stderr, "WriteData FAILED %d %s\n", errno, strerror(errno)); + printf_error("WriteData FAILED %d %s\n", errno, strerror(errno)); return false; } done += written; diff --git a/src/coreclr/debug/createdump/dumpwriterelf.cpp b/src/coreclr/debug/createdump/dumpwriterelf.cpp index afd403212b2..fb4d822c186 100644 --- a/src/coreclr/debug/createdump/dumpwriterelf.cpp +++ b/src/coreclr/debug/createdump/dumpwriterelf.cpp @@ -161,7 +161,7 @@ DumpWriter::WriteDump() // and then laydown the memory blocks if (finalNoteAlignment > 0) { if (finalNoteAlignment > sizeof(m_tempBuffer)) { - fprintf(stderr, "finalNoteAlignment %zu > sizeof(m_tempBuffer)\n", finalNoteAlignment); + printf_error("finalNoteAlignment %zu > sizeof(m_tempBuffer)\n", finalNoteAlignment); return false; } memset(m_tempBuffer, 0, finalNoteAlignment); @@ -189,13 +189,13 @@ DumpWriter::WriteDump() size_t read = 0; if (!m_crashInfo.ReadProcessMemory((void*)address, m_tempBuffer, bytesToRead, &read)) { - fprintf(stderr, "ReadProcessMemory(%" PRIA PRIx64 ", %08zx) FAILED\n", address, bytesToRead); + printf_error("ReadProcessMemory(%" PRIA PRIx64 ", %08zx) FAILED\n", address, bytesToRead); return false; } // This can happen if the target process dies before createdump is finished if (read == 0) { - fprintf(stderr, "ReadProcessMemory(%" PRIA PRIx64 ", %08zx) returned 0 bytes read\n", address, bytesToRead); + printf_error("ReadProcessMemory(%" PRIA PRIx64 ", %08zx) returned 0 bytes read\n", address, bytesToRead); return false; } @@ -209,8 +209,7 @@ DumpWriter::WriteDump() } } - printf("Written %" PRId64 " bytes (%" PRId64 " pages) to core file\n", total, total / PAGE_SIZE); - + printf_status("Written %" PRId64 " bytes (%" PRId64 " pages) to core file\n", total, total / PAGE_SIZE); return true; } diff --git a/src/coreclr/debug/createdump/dumpwritermacho.cpp b/src/coreclr/debug/createdump/dumpwritermacho.cpp index e5cefe9ffbe..fc354d584d0 100644 --- a/src/coreclr/debug/createdump/dumpwritermacho.cpp +++ b/src/coreclr/debug/createdump/dumpwritermacho.cpp @@ -56,7 +56,7 @@ DumpWriter::WriteDump() if (alignment > 0) { if (alignment > sizeof(m_tempBuffer)) { - fprintf(stderr, "Segment alignment %llu > sizeof(m_tempBuffer)\n", alignment); + printf_error("Segment alignment %llu > sizeof(m_tempBuffer)\n", alignment); return false; } memset(m_tempBuffer, 0, alignment); @@ -264,13 +264,13 @@ DumpWriter::WriteSegments() size_t read = 0; if (!m_crashInfo.ReadProcessMemory((void*)address, m_tempBuffer, bytesToRead, &read)) { - fprintf(stderr, "ReadProcessMemory(%" PRIA PRIx64 ", %08zx) FAILED\n", address, bytesToRead); + printf_error("ReadProcessMemory(%" PRIA PRIx64 ", %08zx) FAILED\n", address, bytesToRead); return false; } // This can happen if the target process dies before createdump is finished if (read == 0) { - fprintf(stderr, "ReadProcessMemory(%" PRIA PRIx64 ", %08zx) returned 0 bytes read\n", address, bytesToRead); + printf_error("ReadProcessMemory(%" PRIA PRIx64 ", %08zx) returned 0 bytes read\n", address, bytesToRead); return false; } @@ -284,6 +284,6 @@ DumpWriter::WriteSegments() } } - printf("Written %" PRId64 " bytes (%" PRId64 " pages) to core file\n", total, total / PAGE_SIZE); + printf_status("Written %" PRId64 " bytes (%" PRId64 " pages) to core file\n", total, total / PAGE_SIZE); return true; } diff --git a/src/coreclr/debug/createdump/main.cpp b/src/coreclr/debug/createdump/main.cpp index f91a81ca66c..3b382cbb89c 100644 --- a/src/coreclr/debug/createdump/main.cpp +++ b/src/coreclr/debug/createdump/main.cpp @@ -57,7 +57,7 @@ int __cdecl main(const int argc, const char* argv[]) exitCode = PAL_InitializeDLL(); if (exitCode != 0) { - fprintf(stderr, "PAL initialization FAILED %d\n", exitCode); + printf_error("PAL initialization FAILED %d\n", exitCode); return exitCode; } #endif @@ -152,13 +152,13 @@ int __cdecl main(const int argc, const char* argv[]) { if (::GetTempPathA(MAX_LONGPATH, tmpPath) == 0) { - fprintf(stderr, "GetTempPath failed (0x%08x)", ::GetLastError()); + printf_error("GetTempPath failed (0x%08x)\n", ::GetLastError()); return ::GetLastError(); } exitCode = strcat_s(tmpPath, MAX_LONGPATH, DEFAULT_DUMP_TEMPLATE); if (exitCode != 0) { - fprintf(stderr, "strcat_s failed (%d)", exitCode); + printf_error("strcat_s failed (%d)\n", exitCode); return exitCode; } dumpPathTemplate = tmpPath; @@ -166,7 +166,7 @@ int __cdecl main(const int argc, const char* argv[]) if (CreateDump(dumpPathTemplate, pid, dumpType, minidumpType, crashReport, crashThread, signal)) { - printf("Dump successfully written\n"); + printf_status("Dump successfully written\n"); } else { @@ -179,7 +179,7 @@ int __cdecl main(const int argc, const char* argv[]) else { // if no pid or invalid command line option - fprintf(stderr, "%s", g_help); + printf_error("%s", g_help); exitCode = -1; } #ifdef HOST_UNIX @@ -189,12 +189,35 @@ int __cdecl main(const int argc, const char* argv[]) } void +printf_status(const char* format, ...) +{ + va_list args; + va_start(args, format); + fprintf(stdout, "[createdump] "); + vfprintf(stdout, format, args); + fflush(stdout); + va_end(args); +} + +void +printf_error(const char* format, ...) +{ + va_list args; + va_start(args, format); + fprintf(stderr, "[createdump] "); + vfprintf(stderr, format, args); + fflush(stderr); + va_end(args); +} + +void trace_printf(const char* format, ...) { if (g_diagnostics) { va_list args; va_start(args, format); + fprintf(stdout, "[createdump] "); vfprintf(stdout, format, args); fflush(stdout); va_end(args); @@ -208,6 +231,7 @@ trace_verbose_printf(const char* format, ...) { va_list args; va_start(args, format); + fprintf(stdout, "[createdump] "); vfprintf(stdout, format, args); fflush(stdout); va_end(args); diff --git a/src/coreclr/debug/createdump/threadinfomac.cpp b/src/coreclr/debug/createdump/threadinfomac.cpp index 918f0ae2310..735794600d0 100644 --- a/src/coreclr/debug/createdump/threadinfomac.cpp +++ b/src/coreclr/debug/createdump/threadinfomac.cpp @@ -23,7 +23,7 @@ ThreadInfo::~ThreadInfo() kern_return_t result = ::mach_port_deallocate(mach_task_self(), m_port); if (result != KERN_SUCCESS) { - fprintf(stderr, "~ThreadInfo: mach_port_deallocate FAILED %x %s\n", result, mach_error_string(result)); + printf_error("~ThreadInfo: mach_port_deallocate FAILED %x %s\n", result, mach_error_string(result)); } } @@ -38,7 +38,7 @@ ThreadInfo::Initialize() kern_return_t result = ::thread_get_state(Port(), x86_THREAD_STATE64, (thread_state_t)&m_gpRegisters, &stateCount); if (result != KERN_SUCCESS) { - fprintf(stderr, "thread_get_state(%x) FAILED %x %s\n", m_tid, result, mach_error_string(result)); + printf_error("thread_get_state(%x) FAILED %x %s\n", m_tid, result, mach_error_string(result)); return false; } @@ -46,7 +46,7 @@ ThreadInfo::Initialize() result = ::thread_get_state(Port(), x86_FLOAT_STATE64, (thread_state_t)&m_fpRegisters, &stateCount); if (result != KERN_SUCCESS) { - fprintf(stderr, "thread_get_state(%x) FAILED %x %s\n", m_tid, result, mach_error_string(result)); + printf_error("thread_get_state(%x) FAILED %x %s\n", m_tid, result, mach_error_string(result)); return false; } #elif defined(__aarch64__) @@ -54,7 +54,7 @@ ThreadInfo::Initialize() kern_return_t result = ::thread_get_state(Port(), ARM_THREAD_STATE64, (thread_state_t)&m_gpRegisters, &stateCount); if (result != KERN_SUCCESS) { - fprintf(stderr, "thread_get_state(%x) FAILED %x %s\n", m_tid, result, mach_error_string(result)); + printf_error("thread_get_state(%x) FAILED %x %s\n", m_tid, result, mach_error_string(result)); return false; } @@ -62,7 +62,7 @@ ThreadInfo::Initialize() result = ::thread_get_state(Port(), ARM_NEON_STATE64, (thread_state_t)&m_fpRegisters, &stateCount); if (result != KERN_SUCCESS) { - fprintf(stderr, "thread_get_state(%x) FAILED %x %s\n", m_tid, result, mach_error_string(result)); + printf_error("thread_get_state(%x) FAILED %x %s\n", m_tid, result, mach_error_string(result)); return false; } #else diff --git a/src/coreclr/debug/createdump/threadinfounix.cpp b/src/coreclr/debug/createdump/threadinfounix.cpp index 856dfbb2993..37af34ca283 100644 --- a/src/coreclr/debug/createdump/threadinfounix.cpp +++ b/src/coreclr/debug/createdump/threadinfounix.cpp @@ -69,7 +69,7 @@ ThreadInfo::GetRegistersWithPTrace() struct iovec gpRegsVec = { &m_gpRegisters, sizeof(m_gpRegisters) }; if (ptrace((__ptrace_request)PTRACE_GETREGSET, m_tid, NT_PRSTATUS, &gpRegsVec) == -1) { - fprintf(stderr, "ptrace(PTRACE_GETREGSET, %d, NT_PRSTATUS) FAILED %d (%s)\n", m_tid, errno, strerror(errno)); + printf_error("ptrace(PTRACE_GETREGSET, %d, NT_PRSTATUS) FAILED %d (%s)\n", m_tid, errno, strerror(errno)); return false; } assert(sizeof(m_gpRegisters) == gpRegsVec.iov_len); @@ -80,7 +80,7 @@ ThreadInfo::GetRegistersWithPTrace() #if defined(__arm__) // Some aarch64 kernels may not support NT_FPREGSET for arm processes. We treat this failure as non-fatal. #else - fprintf(stderr, "ptrace(PTRACE_GETREGSET, %d, NT_FPREGSET) FAILED %d (%s)\n", m_tid, errno, strerror(errno)); + printf_error("ptrace(PTRACE_GETREGSET, %d, NT_FPREGSET) FAILED %d (%s)\n", m_tid, errno, strerror(errno)); return false; #endif } @@ -89,7 +89,7 @@ ThreadInfo::GetRegistersWithPTrace() #if defined(__i386__) if (ptrace((__ptrace_request)PTRACE_GETFPXREGS, m_tid, nullptr, &m_fpxRegisters) == -1) { - fprintf(stderr, "ptrace(GETFPXREGS, %d) FAILED %d (%s)\n", m_tid, errno, strerror(errno)); + printf_error("ptrace(GETFPXREGS, %d) FAILED %d (%s)\n", m_tid, errno, strerror(errno)); return false; } #elif defined(__arm__) && defined(__VFP_FP__) && !defined(__SOFTFP__) @@ -100,7 +100,7 @@ ThreadInfo::GetRegistersWithPTrace() if (ptrace((__ptrace_request)PTRACE_GETVFPREGS, m_tid, nullptr, &m_vfpRegisters) == -1) { - fprintf(stderr, "ptrace(PTRACE_GETVFPREGS, %d) FAILED %d (%s)\n", m_tid, errno, strerror(errno)); + printf_error("ptrace(PTRACE_GETVFPREGS, %d) FAILED %d (%s)\n", m_tid, errno, strerror(errno)); return false; } #endif diff --git a/src/coreclr/pal/src/thread/process.cpp b/src/coreclr/pal/src/thread/process.cpp index f31449fb19c..22e0fe6eece 100644 --- a/src/coreclr/pal/src/thread/process.cpp +++ b/src/coreclr/pal/src/thread/process.cpp @@ -3286,6 +3286,8 @@ PROCAbortInitialize() char* dumpType = getenv("COMPlus_DbgMiniDumpType"); char* diagStr = getenv("COMPlus_CreateDumpDiagnostics"); BOOL diag = diagStr != nullptr && strcmp(diagStr, "1") == 0; + char* verboseStr = getenv("COMPlus_CreateDumpVerboseDiagnostics"); + BOOL verbose = verboseStr != nullptr && strcmp(verboseStr, "1") == 0; char* crashReportStr = getenv("COMPlus_EnableCrashReport"); BOOL crashReport = crashReportStr != nullptr && strcmp(crashReportStr, "1") == 0; ULONG32 flags = GenerateDumpFlagsNone; @@ -3293,6 +3295,10 @@ PROCAbortInitialize() { flags |= GenerateDumpFlagsLoggingEnabled; } + if (verbose) + { + flags |= GenerateDumpFlagsVerboseLoggingEnabled; + } if (crashReport) { flags |= GenerateDumpFlagsCrashReportEnabled; diff --git a/src/coreclr/vm/threads.h b/src/coreclr/vm/threads.h index af2a7b32d31..acc23de0cbd 100644 --- a/src/coreclr/vm/threads.h +++ b/src/coreclr/vm/threads.h @@ -3292,6 +3292,14 @@ private: static void __stdcall RedirectedHandledJITCaseForGCStress(); #endif // defined(HAVE_GCCOVER) && USE_REDIRECT_FOR_GCSTRESS +#ifdef TARGET_X86 + // RtlRestoreContext is available on x86, but relatively recently. + // RestoreContextSimulated uses SEH machinery for a similar result on legacy OS-es. + // This function should not be used on new OS-es as the pattern is not + // guaranteed to continue working in the future. + static void RestoreContextSimulated(Thread* pThread, CONTEXT* pCtx, void* pFrame, DWORD dwLastError); +#endif + friend void CPFH_AdjustContextForThreadSuspensionRace(T_CONTEXT *pContext, Thread *pThread); #endif // FEATURE_HIJACK && !TARGET_UNIX diff --git a/src/coreclr/vm/threadsuspend.cpp b/src/coreclr/vm/threadsuspend.cpp index 57318e29e89..b92af380085 100644 --- a/src/coreclr/vm/threadsuspend.cpp +++ b/src/coreclr/vm/threadsuspend.cpp @@ -1948,6 +1948,9 @@ typedef BOOL(WINAPI* PINITIALIZECONTEXT2)(PVOID Buffer, DWORD ContextFlags, PCON PINITIALIZECONTEXT2 pfnInitializeContext2 = NULL; #ifdef TARGET_X86 +typedef VOID(__cdecl* PRTLRESTORECONTEXT)(PCONTEXT ContextRecord, struct _EXCEPTION_RECORD* ExceptionRecord); +PRTLRESTORECONTEXT pfnRtlRestoreContext = NULL; + #define CONTEXT_COMPLETE (CONTEXT_FULL | CONTEXT_FLOATING_POINT | \ CONTEXT_DEBUG_REGISTERS | CONTEXT_EXTENDED_REGISTERS | CONTEXT_EXCEPTION_REQUEST) #else @@ -1960,7 +1963,6 @@ CONTEXT* AllocateOSContextHelper(BYTE** contextBuffer) #if !defined(TARGET_UNIX) && (defined(TARGET_X86) || defined(TARGET_AMD64)) DWORD context = CONTEXT_COMPLETE; - BOOL supportsAVX = FALSE; if (pfnInitializeContext2 == NULL) { @@ -1968,13 +1970,20 @@ CONTEXT* AllocateOSContextHelper(BYTE** contextBuffer) pfnInitializeContext2 = (PINITIALIZECONTEXT2)GetProcAddress(hm, "InitializeContext2"); } - // Determine if the processor supports AVX so we could +#ifdef TARGET_X86 + if (pfnRtlRestoreContext == NULL) + { + HMODULE hm = GetModuleHandleW(_T("ntdll.dll")); + pfnRtlRestoreContext = (PRTLRESTORECONTEXT)GetProcAddress(hm, "RtlRestoreContext"); + } +#endif //TARGET_X86 + + // Determine if the processor supports AVX so we could // retrieve extended registers DWORD64 FeatureMask = GetEnabledXStateFeatures(); if ((FeatureMask & XSTATE_MASK_AVX) != 0) { context = context | CONTEXT_XSTATE; - supportsAVX = TRUE; } // Retrieve contextSize by passing NULL for Buffer @@ -1985,9 +1994,14 @@ CONTEXT* AllocateOSContextHelper(BYTE** contextBuffer) pfnInitializeContext2(NULL, context, NULL, &contextSize, xStateCompactionMask) : InitializeContext(NULL, context, NULL, &contextSize); - // The following assert is valid, but gets triggered in some Win7 runs with no impact on functionality. - // commenting this out to reduce noise, as long as Win7 is supported. - // _ASSERTE(!success && GetLastError() == ERROR_INSUFFICIENT_BUFFER); + // Spec mentions that we may get a different error (it was observed on Windows7). + // In such case the contextSize is undefined. + if (success || GetLastError() != ERROR_INSUFFICIENT_BUFFER) + { + STRESS_LOG2(LF_SYNC, LL_INFO1000, "AllocateOSContextHelper: Unexpected result from InitializeContext (success: %d, error: %d).\n", + success, GetLastError()); + return NULL; + } // So now allocate a buffer of that size and call InitializeContext again BYTE* buffer = new (nothrow)BYTE[contextSize]; @@ -1997,15 +2011,6 @@ CONTEXT* AllocateOSContextHelper(BYTE** contextBuffer) pfnInitializeContext2(buffer, context, &pOSContext, &contextSize, xStateCompactionMask): InitializeContext(buffer, context, &pOSContext, &contextSize); - // if AVX is supported set the appropriate features mask in the context - if (success && supportsAVX) - { - // This should not normally fail. - // The system silently ignores any feature specified in the FeatureMask - // which is not enabled on the processor. - success = SetXStateFeaturesMask(pOSContext, XSTATE_MASK_AVX); - } - if (!success) { delete[] buffer; @@ -2509,6 +2514,7 @@ void RedirectedThreadFrame::ExceptionUnwind() #ifndef TARGET_UNIX #ifdef TARGET_X86 + //**************************************************************************************** // This will check who caused the exception. If it was caused by the the redirect function, // the reason is to resume the thread back at the point it was redirected in the first @@ -2520,18 +2526,18 @@ void RedirectedThreadFrame::ExceptionUnwind() int RedirectedHandledJITCaseExceptionFilter( PEXCEPTION_POINTERS pExcepPtrs, // Exception data RedirectedThreadFrame *pFrame, // Frame on stack - BOOL fDone, // Whether redirect completed without exception - CONTEXT *pCtx) // Saved context + CONTEXT *pCtx, // Saved context + DWORD dwLastError) // saved last error { // !!! Do not use a non-static contract here. // !!! Contract may insert an exception handling record. // !!! This function assumes that GetCurrentSEHRecord() returns the exception record set up in - // !!! Thread::RedirectedHandledJITCase + // !!! Thread::RestoreContextSimulated // // !!! Do not use an object with dtor, since it injects a fs:0 entry. STATIC_CONTRACT_NOTHROW; STATIC_CONTRACT_GC_TRIGGERS; - STATIC_CONTRACT_MODE_ANY; + STATIC_CONTRACT_MODE_COOPERATIVE; if (pExcepPtrs->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW) { @@ -2540,44 +2546,22 @@ int RedirectedHandledJITCaseExceptionFilter( // Get the thread handle Thread *pThread = GetThread(); - - STRESS_LOG2(LF_SYNC, LL_INFO100, "In RedirectedHandledJITCaseExceptionFilter fDone = %d pFrame = %p\n", fDone, pFrame); - - // If we get here via COM+ exception, gc-mode is unknown. We need it to - // be cooperative for this function. - GCX_COOP_NO_DTOR(); - - // If the exception was due to the called client, then we need to figure out if it - // is an exception that can be eaten or if it needs to be handled elsewhere. - if (!fDone) - { - if (pExcepPtrs->ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE) - { - return (EXCEPTION_CONTINUE_SEARCH); - } - - // Get the latest thrown object - OBJECTREF throwable = CLRException::GetThrowableFromExceptionRecord(pExcepPtrs->ExceptionRecord); - - // If this is an uncatchable exception, then let the exception be handled elsewhere - if (IsUncatchable(&throwable)) - { - pThread->EnablePreemptiveGC(); - return (EXCEPTION_CONTINUE_SEARCH); - } - } -#ifdef _DEBUG - else - { - _ASSERTE(pExcepPtrs->ExceptionRecord->ExceptionCode == EXCEPTION_HIJACK); - } -#endif + STRESS_LOG1(LF_SYNC, LL_INFO100, "In RedirectedHandledJITCaseExceptionFilter pFrame = %p\n", pFrame); + _ASSERTE(pExcepPtrs->ExceptionRecord->ExceptionCode == EXCEPTION_HIJACK); // Unlink the frame in preparation for resuming in managed code pFrame->Pop(); - // Copy the saved context record into the EH context; - ReplaceExceptionContextRecord(pExcepPtrs->ContextRecord, pCtx); + // Copy everything in the saved context record into the EH context. + // Historically the EH context has enough space for every enabled context feature. + // That may not hold for the future features beyond AVX, but this codepath is + // supposed to be used only on OSes that do not have RtlRestoreContext. + CONTEXT* pTarget = pExcepPtrs->ContextRecord; + if (!CopyContext(pTarget, pCtx->ContextFlags, pCtx)) + { + STRESS_LOG1(LF_SYNC, LL_ERROR, "ERROR: Could not set context record, lastError = 0x%x\n", GetLastError()); + EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE); + } DWORD espValue = pCtx->Esp; @@ -2607,6 +2591,9 @@ int RedirectedHandledJITCaseExceptionFilter( // Register the special OS handler as the top handler with the OS SetCurrentSEHRecord(pCurSEH); + // restore last error + SetLastError(dwLastError); + // Resume execution at point where thread was originally redirected return (EXCEPTION_CONTINUE_EXECUTION); } @@ -2639,6 +2626,38 @@ extern "C" PCONTEXT __stdcall GetCurrentSavedRedirectContext() return pContext; } +#ifdef TARGET_X86 + +void Thread::RestoreContextSimulated(Thread* pThread, CONTEXT* pCtx, void* pFrame, DWORD dwLastError) +{ + pThread->HandleThreadAbort(); // Might throw an exception. + + // A counter to avoid a nasty case where an + // up-stack filter throws another exception + // causing our filter to be run again for + // some unrelated exception. + int filter_count = 0; + + __try + { + // Save the instruction pointer where we redirected last. This does not race with the check + // against this variable in HandledJitCase because the GC will not attempt to redirect the + // thread until the instruction pointer of this thread is back in managed code. + pThread->m_LastRedirectIP = GetIP(pCtx); + pThread->m_SpinCount = 0; + + RaiseException(EXCEPTION_HIJACK, 0, 0, NULL); + } + __except (++filter_count == 1 + ? RedirectedHandledJITCaseExceptionFilter(GetExceptionInformation(), (RedirectedThreadFrame*)pFrame, pCtx, dwLastError) + : EXCEPTION_CONTINUE_SEARCH) + { + _ASSERTE(!"Reached body of __except in Thread::RedirectedHandledJITCase"); + } +} + +#endif // TARGET_X86 + void __stdcall Thread::RedirectedHandledJITCase(RedirectReason reason) { STATIC_CONTRACT_THROWS; @@ -2662,140 +2681,106 @@ void __stdcall Thread::RedirectedHandledJITCase(RedirectReason reason) STRESS_LOG5(LF_SYNC, LL_INFO1000, "In RedirectedHandledJITcase reason 0x%x pFrame = %p pc = %p sp = %p fp = %p", reason, &frame, GetIP(pCtx), GetSP(pCtx), GetFP(pCtx)); -#ifdef TARGET_X86 - // This will indicate to the exception filter whether or not the exception is caused - // by us or the client. - BOOL fDone = FALSE; - int filter_count = 0; // A counter to avoid a nasty case where an - // up-stack filter throws another exception - // causing our filter to be run again for - // some unrelated exception. - - __try -#endif // TARGET_X86 - { - // Make sure this thread doesn't reuse the context memory. - pThread->MarkRedirectContextInUse(pCtx); + // Make sure this thread doesn't reuse the context memory. + pThread->MarkRedirectContextInUse(pCtx); - // Link in the frame - frame.Push(); + // Link in the frame + frame.Push(); #if defined(HAVE_GCCOVER) && defined(USE_REDIRECT_FOR_GCSTRESS) // GCCOVER - if (reason == RedirectReason_GCStress) - { - _ASSERTE(pThread->PreemptiveGCDisabledOther()); - DoGcStress(frame.GetContext(), NULL); - } - else + if (reason == RedirectReason_GCStress) + { + _ASSERTE(pThread->PreemptiveGCDisabledOther()); + DoGcStress(frame.GetContext(), NULL); + } + else #endif // HAVE_GCCOVER && USE_REDIRECT_FOR_GCSTRESS - { - // Enable PGC before calling out to the client to allow runtime suspend to finish - GCX_PREEMP_NO_DTOR(); + { + _ASSERTE(reason == RedirectReason_GCSuspension || + reason == RedirectReason_DebugSuspension || + reason == RedirectReason_UserSuspension); - // Notify the interface of the pending suspension - switch (reason) { - case RedirectReason_GCSuspension: - break; - case RedirectReason_DebugSuspension: - break; - case RedirectReason_UserSuspension: - // Do nothing; - break; - default: - _ASSERTE(!"Invalid redirect reason"); - break; - } + // Actual self-suspension. + // Leave and reenter COOP mode to be trapped on the way back. + GCX_PREEMP_NO_DTOR(); + GCX_PREEMP_NO_DTOR_END(); + } - // Disable preemptive GC so we can unlink the frame - GCX_PREEMP_NO_DTOR_END(); - } + // Once we get here the suspension is over! + // We will restore the state as it was at the point of redirection + // and continue normal execution. #ifdef TARGET_X86 - pThread->HandleThreadAbort(); // Might throw an exception. - - // Indicate that the call to the service went without an exception, and that - // we're raising our own exception to resume the thread to where it was - // redirected from - fDone = TRUE; - - // Save the instruction pointer where we redirected last. This does not race with the check - // against this variable in HandledJitCase because the GC will not attempt to redirect the - // thread until the instruction pointer of this thread is back in managed code. - pThread->m_LastRedirectIP = GetIP(pCtx); - pThread->m_SpinCount = 0; - - RaiseException(EXCEPTION_HIJACK, 0, 0, NULL); + if (!pfnRtlRestoreContext) + { + RestoreContextSimulated(pThread, pCtx, &frame, dwLastError); -#else // TARGET_X86 + // we never return to the caller. + __UNREACHABLE(); + } +#endif // TARGET_X86 #if defined(HAVE_GCCOVER) && defined(USE_REDIRECT_FOR_GCSTRESS) // GCCOVER - // - // If GCStress interrupts an IL stub or inlined p/invoke while it's running in preemptive mode, it switches the mode to - // cooperative - but we will resume to preemptive below. We should not trigger an abort in that case, as it will fail - // due to the GC mode. - // - if (!pThread->m_fPreemptiveGCDisabledForGCStress) + // + // If GCStress interrupts an IL stub or inlined p/invoke while it's running in preemptive mode, it switches the mode to + // cooperative - but we will resume to preemptive below. We should not trigger an abort in that case, as it will fail + // due to the GC mode. + // + if (!pThread->m_fPreemptiveGCDisabledForGCStress) #endif - { + { - UINT_PTR uAbortAddr; - UINT_PTR uResumePC = (UINT_PTR)GetIP(pCtx); - CopyOSContext(pThread->m_OSContext, pCtx); - uAbortAddr = (UINT_PTR)COMPlusCheckForAbort(); - if (uAbortAddr) - { - LOG((LF_EH, LL_INFO100, "thread abort in progress, resuming thread under control... (handled jit case)\n")); + UINT_PTR uAbortAddr; + UINT_PTR uResumePC = (UINT_PTR)GetIP(pCtx); + CopyOSContext(pThread->m_OSContext, pCtx); + uAbortAddr = (UINT_PTR)COMPlusCheckForAbort(); + if (uAbortAddr) + { + LOG((LF_EH, LL_INFO100, "thread abort in progress, resuming thread under control... (handled jit case)\n")); - CONSISTENCY_CHECK(CheckPointer(pCtx)); + CONSISTENCY_CHECK(CheckPointer(pCtx)); - STRESS_LOG1(LF_EH, LL_INFO10, "resume under control: ip: %p (handled jit case)\n", uResumePC); + STRESS_LOG1(LF_EH, LL_INFO10, "resume under control: ip: %p (handled jit case)\n", uResumePC); - SetIP(pThread->m_OSContext, uResumePC); + SetIP(pThread->m_OSContext, uResumePC); #if defined(TARGET_ARM) - // Save the original resume PC in Lr - pCtx->Lr = uResumePC; + // Save the original resume PC in Lr + pCtx->Lr = uResumePC; - // Since we have set a new IP, we have to clear conditional execution flags too. - ClearITState(pThread->m_OSContext); + // Since we have set a new IP, we have to clear conditional execution flags too. + ClearITState(pThread->m_OSContext); #endif // TARGET_ARM - SetIP(pCtx, uAbortAddr); - } + SetIP(pCtx, uAbortAddr); } + } - // Unlink the frame in preparation for resuming in managed code - frame.Pop(); + // Unlink the frame in preparation for resuming in managed code + frame.Pop(); - { - // Allow future use of the context - pThread->UnmarkRedirectContextInUse(pCtx); + // Allow future use of the context + pThread->UnmarkRedirectContextInUse(pCtx); #if defined(HAVE_GCCOVER) && defined(USE_REDIRECT_FOR_GCSTRESS) // GCCOVER - if (pThread->m_fPreemptiveGCDisabledForGCStress) - { - pThread->EnablePreemptiveGC(); - pThread->m_fPreemptiveGCDisabledForGCStress = false; - } + if (pThread->m_fPreemptiveGCDisabledForGCStress) + { + pThread->EnablePreemptiveGC(); + pThread->m_fPreemptiveGCDisabledForGCStress = false; + } #endif - LOG((LF_SYNC, LL_INFO1000, "Resuming execution with RtlRestoreContext\n")); - - SetLastError(dwLastError); // END_PRESERVE_LAST_ERROR + LOG((LF_SYNC, LL_INFO1000, "Resuming execution with RtlRestoreContext\n")); + SetLastError(dwLastError); // END_PRESERVE_LAST_ERROR - RtlRestoreContext(pCtx, NULL); - } -#endif // TARGET_X86 - } #ifdef TARGET_X86 - __except (++filter_count == 1 - ? RedirectedHandledJITCaseExceptionFilter(GetExceptionInformation(), &frame, fDone, pCtx) - : EXCEPTION_CONTINUE_SEARCH) - { - _ASSERTE(!"Reached body of __except in Thread::RedirectedHandledJITCase"); - } + pfnRtlRestoreContext(pCtx, NULL); +#else + RtlRestoreContext(pCtx, NULL); +#endif -#endif // TARGET_X86 + // we never return to the caller. + __UNREACHABLE(); } //**************************************************************************************** @@ -2898,14 +2883,34 @@ BOOL Thread::RedirectThreadAtHandledJITCase(PFN_REDIRECTTARGET pTgt) if (!pCtx) { pCtx = m_pSavedRedirectContext = ThreadStore::GrabOSContext(&m_pOSContextBuffer); - _ASSERTE(GetSavedRedirectContext() != NULL); } + // We may not have a preallocated context. Could be short on memory when we tried to preallocate. + // We cannot allocate here since we have a thread stopped in a random place, possibly holding locks + // that we would need while allocating. + // Other ways and attempts at suspending may yet succeed, but this redirection cannot continue. + if (!pCtx) + return (FALSE); + ////////////////////////////////////// // Get and save the thread's context + BOOL bRes = true; // Always get complete context, pCtx->ContextFlags are set during Initialization - BOOL bRes = EEGetThreadContext(this, pCtx); + +#if defined(TARGET_X86) || defined(TARGET_AMD64) + // Scenarios like GC stress may indirectly disable XState features in the pCtx + // depending on the state at the time of GC stress interrupt. + // + // Make sure that AVX feature mask is set, if supported. + // + // This should not normally fail. + // The system silently ignores any feature specified in the FeatureMask + // which is not enabled on the processor. + bRes &= SetXStateFeaturesMask(pCtx, XSTATE_MASK_AVX); +#endif //defined(TARGET_X86) || defined(TARGET_AMD64) + + bRes &= EEGetThreadContext(this, pCtx); _ASSERTE(bRes && "Failed to GetThreadContext in RedirectThreadAtHandledJITCase - aborting redirect."); if (!bRes) @@ -3020,8 +3025,35 @@ BOOL Thread::RedirectCurrentThreadAtHandledJITCase(PFN_REDIRECTTARGET pTgt, CONT ////////////////////////////////////// // Get and save the thread's context - BOOL success = CopyContext(pCtx, pCtx->ContextFlags, pCurrentThreadCtx); + BOOL success = TRUE; + +#if defined(TARGET_X86) || defined(TARGET_AMD64) + // This method is called for GC stress interrupts in managed code. + // The current context may have various XState features, depending on what is used/dirty, + // but only AVX feature may contain live data. (that could change with new features in JIT) + // Besides pCtx may not have space to store other features. + // So we will mask out everything but AVX. + DWORD64 srcFeatures = 0; + success = GetXStateFeaturesMask(pCurrentThreadCtx, &srcFeatures); _ASSERTE(success); + if (!success) + return FALSE; + + // Get may return 0 if no XState is set, which Set would not accept. + if (srcFeatures != 0) + { + success = SetXStateFeaturesMask(pCurrentThreadCtx, srcFeatures & XSTATE_MASK_AVX); + _ASSERTE(success); + if (!success) + return FALSE; + } + +#endif //defined(TARGET_X86) || defined(TARGET_AMD64) + + success = CopyContext(pCtx, pCtx->ContextFlags, pCurrentThreadCtx); + _ASSERTE(success); + if (!success) + return FALSE; // Ensure that this flag is set for the next time through the normal path, // RedirectThreadAtHandledJITCase. |