Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordotnet-bot <dotnet-bot@microsoft.com>2022-03-09 01:18:37 +0300
committerdotnet-bot <dotnet-bot@microsoft.com>2022-03-09 01:18:37 +0300
commitef034e703d270205e149e330cf5355b7dc913a4c (patch)
treeb923c7116d46be217dd61256a5829a082f282231
parenta31025a0f875d1b7974ec86f4c6364c27b62d42d (diff)
parent3a14bd70a3d63649f711cb8ef196e8467bfa68de (diff)
Merge in 'release/6.0' changes
-rw-r--r--src/coreclr/debug/createdump/crashinfo.cpp16
-rw-r--r--src/coreclr/debug/createdump/crashinfomac.cpp6
-rw-r--r--src/coreclr/debug/createdump/crashinfounix.cpp12
-rw-r--r--src/coreclr/debug/createdump/crashreportwriter.cpp6
-rw-r--r--src/coreclr/debug/createdump/createdump.h2
-rw-r--r--src/coreclr/debug/createdump/createdumpunix.cpp8
-rw-r--r--src/coreclr/debug/createdump/createdumpwindows.cpp10
-rw-r--r--src/coreclr/debug/createdump/dumpname.cpp6
-rw-r--r--src/coreclr/debug/createdump/dumpwriter.cpp4
-rw-r--r--src/coreclr/debug/createdump/dumpwriterelf.cpp9
-rw-r--r--src/coreclr/debug/createdump/dumpwritermacho.cpp8
-rw-r--r--src/coreclr/debug/createdump/main.cpp34
-rw-r--r--src/coreclr/debug/createdump/threadinfomac.cpp10
-rw-r--r--src/coreclr/debug/createdump/threadinfounix.cpp8
-rw-r--r--src/coreclr/pal/src/thread/process.cpp6
-rw-r--r--src/coreclr/vm/threads.h8
-rw-r--r--src/coreclr/vm/threadsuspend.cpp350
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.