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:
authorMike McLaughlin <mikem@microsoft.com>2021-07-08 02:34:17 +0300
committerGitHub <noreply@github.com>2021-07-08 02:34:17 +0300
commit3d10d70a450e13d7cdbf1f843ff0b6bf768448cc (patch)
tree3a1577c4446ec728ecbda7ea8474e4fb9e69d620 /src/coreclr/pal
parent0ef56df4a7c0753296a736b071946d6bc833fdc2 (diff)
Add crash report file for VS4Mac Watson (#54934)
Add crash report file for VS4Mac Watson Add the --crashreport createdump command line option to enable this feature. Add crash thread (--crashthread) and signal number (--signal) command line options. Use std::vector for g_argCreateDump. Add the COMPlus_EnableCrashReport environment variable to enable this feature. Add simple json writer (JsonWriter). Remote unwinder: special case when encoding == 0 and IP after syscall opcode to popping return address Remove unwinder: add functionStart return from remote unwind API Add ModuleInfo struct containing the info about a native or managed module. Add StackFrame struct containing the info about a native or managed stack frame. Add signal number to PROCAbort. Currently the Linux crash report is stubbed out (empty). Better createdump logging. Add CrashReportWriter class.
Diffstat (limited to 'src/coreclr/pal')
-rw-r--r--src/coreclr/pal/inc/pal.h2
-rw-r--r--src/coreclr/pal/src/exception/remote-unwind.cpp82
-rw-r--r--src/coreclr/pal/src/exception/signal.cpp11
-rw-r--r--src/coreclr/pal/src/include/pal/process.h10
-rw-r--r--src/coreclr/pal/src/thread/process.cpp128
5 files changed, 180 insertions, 53 deletions
diff --git a/src/coreclr/pal/inc/pal.h b/src/coreclr/pal/inc/pal.h
index 532c3e82d3d..cd96f5753cc 100644
--- a/src/coreclr/pal/inc/pal.h
+++ b/src/coreclr/pal/inc/pal.h
@@ -2410,7 +2410,7 @@ typedef BOOL(*UnwindReadMemoryCallback)(PVOID address, PVOID buffer, SIZE_T size
PALIMPORT BOOL PALAPI PAL_VirtualUnwind(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextPointers);
-PALIMPORT BOOL PALAPI PAL_VirtualUnwindOutOfProc(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextPointers, SIZE_T baseAddress, UnwindReadMemoryCallback readMemoryCallback);
+PALIMPORT BOOL PALAPI PAL_VirtualUnwindOutOfProc(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextPointers, PULONG64 functionStart, SIZE_T baseAddress, UnwindReadMemoryCallback readMemoryCallback);
#define GetLogicalProcessorCacheSizeFromOS PAL_GetLogicalProcessorCacheSizeFromOS
diff --git a/src/coreclr/pal/src/exception/remote-unwind.cpp b/src/coreclr/pal/src/exception/remote-unwind.cpp
index b82960cc723..af0293ba5bc 100644
--- a/src/coreclr/pal/src/exception/remote-unwind.cpp
+++ b/src/coreclr/pal/src/exception/remote-unwind.cpp
@@ -164,6 +164,7 @@ typedef struct _libunwindInfo
{
SIZE_T BaseAddress;
CONTEXT *Context;
+ ULONG64 FunctionStart;
UnwindReadMemoryCallback ReadMemory;
} libunwindInfo;
@@ -957,7 +958,7 @@ ExtractProcInfoFromFde(
static bool
SearchCompactEncodingSection(
- const libunwindInfo* info,
+ libunwindInfo* info,
unw_word_t ip,
unw_word_t compactUnwindSectionAddr,
unw_proc_info_t *pip)
@@ -966,7 +967,11 @@ SearchCompactEncodingSection(
if (!info->ReadMemory((PVOID)compactUnwindSectionAddr, &sectionHeader, sizeof(sectionHeader))) {
return false;
}
- TRACE("Unwind ver %d common off: %08x common cnt: %d pers off: %08x pers cnt: %d index off: %08x index cnt: %d\n",
+ int32_t offset = ip - info->BaseAddress;
+
+ TRACE("Unwind %p offset %08x ver %d common off: %08x common cnt: %d pers off: %08x pers cnt: %d index off: %08x index cnt: %d\n",
+ (void*)compactUnwindSectionAddr,
+ offset,
sectionHeader.version,
sectionHeader.commonEncodingsArraySectionOffset,
sectionHeader.commonEncodingsArrayCount,
@@ -979,7 +984,6 @@ SearchCompactEncodingSection(
return false;
}
- int32_t offset = ip - info->BaseAddress;
unwind_info_section_header_index_entry entry;
unwind_info_section_header_index_entry entryNext;
bool found;
@@ -1060,6 +1064,8 @@ SearchCompactEncodingSection(
TRACE("Second level compressed pageEntry not found start %p end %p\n", (void*)funcStart, (void*)funcEnd);
}
+ TRACE("Second level compressed: funcStart %p funcEnd %p pageEntry %08x pageEntryNext %08x\n", (void*)funcStart, (void*)funcEnd, pageEntry, pageEntryNext);
+
if (ip < funcStart || ip > funcEnd) {
ERROR("ip %p not in compressed second level\n", (void*)ip);
return false;
@@ -1073,7 +1079,7 @@ SearchCompactEncodingSection(
if (!ReadValue32(info, &addr, &encoding)) {
return false;
}
- TRACE("Second level compressed common table: %08x for offset %08x\n", encoding, pageOffset);
+ TRACE("Second level compressed common table: %08x for offset %08x encodingIndex %d\n", encoding, pageOffset, encodingIndex);
}
else
{
@@ -1134,6 +1140,7 @@ SearchCompactEncodingSection(
}
}
+ info->FunctionStart = funcStart;
pip->start_ip = funcStart;
pip->end_ip = funcEnd;
pip->lsda = lsda;
@@ -1171,6 +1178,7 @@ SearchDwarfSection(
ERROR("ExtractFde FAILED for ip %p\n", (void*)ip);
break;
}
+
if (ip >= ipStart && ip < ipEnd) {
if (!ExtractProcInfoFromFde(info, &fdeAddr, pip, need_unwind_info)) {
ERROR("ExtractProcInfoFromFde FAILED for ip %p\n", (void*)ip);
@@ -1185,7 +1193,7 @@ SearchDwarfSection(
static bool
-GetProcInfo(unw_word_t ip, unw_proc_info_t *pip, const libunwindInfo* info, bool* step, int need_unwind_info)
+GetProcInfo(unw_word_t ip, unw_proc_info_t *pip, libunwindInfo* info, bool* step, int need_unwind_info)
{
memset(pip, 0, sizeof(*pip));
*step = false;
@@ -1297,11 +1305,12 @@ GetProcInfo(unw_word_t ip, unw_proc_info_t *pip, const libunwindInfo* info, bool
}
}
- ERROR("Unwind info not found for %p format %08x\n", (void*)ip, pip->format);
+ ERROR("Unwind info not found for %p format %08x ehframeSectionAddr %p ehframeSectionSize %p\n", (void*)ip, pip->format, (void*)ehframeSectionAddr, (void*)ehframeSectionSize);
return false;
}
#if defined(TARGET_AMD64)
+
static bool
StepWithCompactEncodingRBPFrame(const libunwindInfo* info, compact_unwind_encoding_t compactEncoding)
{
@@ -1370,9 +1379,49 @@ StepWithCompactEncodingRBPFrame(const libunwindInfo* info, compact_unwind_encodi
compactEncoding, (void*)context->Rip, (void*)context->Rsp, (void*)context->Rbp);
return true;
}
-#endif
+
+#define AMD64_SYSCALL_OPCODE 0x050f
+
+static bool
+StepWithCompactNoEncoding(const libunwindInfo* info)
+{
+ // We get here because we found the function the IP is in the compact unwind info, but the encoding is 0. This
+ // usually ends the unwind but here we check that the function is a syscall "wrapper" and assume there is no
+ // frame and pop the return address.
+ uint16_t opcode;
+ unw_word_t addr = info->Context->Rip - sizeof(opcode);
+ if (!ReadValue16(info, &addr, &opcode)) {
+ return false;
+ }
+ // Is the IP pointing just after a "syscall" opcode?
+ if (opcode != AMD64_SYSCALL_OPCODE) {
+ // There are cases where the IP points one byte after the syscall; not sure why.
+ addr = info->Context->Rip - sizeof(opcode) + 1;
+ if (!ReadValue16(info, &addr, &opcode)) {
+ return false;
+ }
+ // Is the IP pointing just after a "syscall" opcode + 1?
+ if (opcode != AMD64_SYSCALL_OPCODE) {
+ ERROR("StepWithCompactNoEncoding: not in syscall wrapper function\n");
+ return false;
+ }
+ }
+ // Pop the return address from the stack
+ uint64_t ip;
+ addr = info->Context->Rsp;
+ if (!ReadValue64(info, &addr, &ip)) {
+ return false;
+ }
+ info->Context->Rip = ip;
+ info->Context->Rsp += sizeof(uint64_t);
+ TRACE("StepWithCompactNoEncoding: SUCCESS new rip %p rsp %p\n", (void*)info->Context->Rip, (void*)info->Context->Rsp);
+ return true;
+}
+
+#endif // TARGET_AMD64
#if defined(TARGET_ARM64)
+
inline static bool
ReadCompactEncodingRegister(const libunwindInfo* info, unw_word_t* addr, DWORD64* reg)
{
@@ -1502,7 +1551,8 @@ StepWithCompactEncodingArm64(const libunwindInfo* info, compact_unwind_encoding_
compactEncoding, (void*)context->Pc, (void*)context->Sp, (void*)context->Fp, (void*)context->Lr);
return true;
}
-#endif
+
+#endif // TARGET_ARM64
static bool
StepWithCompactEncoding(const libunwindInfo* info, compact_unwind_encoding_t compactEncoding, unw_word_t functionStart)
@@ -1510,8 +1560,7 @@ StepWithCompactEncoding(const libunwindInfo* info, compact_unwind_encoding_t com
#if defined(TARGET_AMD64)
if (compactEncoding == 0)
{
- TRACE("Compact unwind missing for %p\n", (void*)info->Context->Rip);
- return false;
+ return StepWithCompactNoEncoding(info);
}
switch (compactEncoding & UNWIND_X86_64_MODE_MASK)
{
@@ -1817,7 +1866,7 @@ get_proc_name(unw_addr_space_t as, unw_word_t addr, char *bufp, size_t buf_len,
static int
find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pip, int need_unwind_info, void *arg)
{
- const auto *info = (libunwindInfo*)arg;
+ auto *info = (libunwindInfo*)arg;
#ifdef __APPLE__
bool step;
if (!GetProcInfo(ip, pip, info, &step, need_unwind_info)) {
@@ -1999,6 +2048,7 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pip, int nee
TRACE("ip %p not in range start_ip %p end_ip %p\n", ip, pip->start_ip, pip->end_ip);
return -UNW_ENOINFO;
}
+ info->FunctionStart = pip->start_ip;
return UNW_ESUCCESS;
#else
return _OOP_find_proc_info(start_ip, end_ip, ehFrameHdrAddr, ehFrameHdrLen, exidxFrameHdrAddr, exidxFrameHdrLen, as, ip, pip, need_unwind_info, arg);
@@ -2048,12 +2098,13 @@ Function:
Parameters:
context - the start context in the target
contextPointers - the context of the next frame
+ functionStart - the pointer to return the starting address of the function or nullptr
baseAddress - base address of the module to find the unwind info
readMemoryCallback - reads memory from the target
--*/
BOOL
PALAPI
-PAL_VirtualUnwindOutOfProc(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextPointers, SIZE_T baseAddress, UnwindReadMemoryCallback readMemoryCallback)
+PAL_VirtualUnwindOutOfProc(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextPointers, PULONG64 functionStart, SIZE_T baseAddress, UnwindReadMemoryCallback readMemoryCallback)
{
unw_addr_space_t addrSpace = 0;
unw_cursor_t cursor;
@@ -2063,6 +2114,7 @@ PAL_VirtualUnwindOutOfProc(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *cont
info.BaseAddress = baseAddress;
info.Context = context;
+ info.FunctionStart = 0;
info.ReadMemory = readMemoryCallback;
#ifdef __APPLE__
@@ -2113,6 +2165,10 @@ PAL_VirtualUnwindOutOfProc(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *cont
result = TRUE;
exit:
+ if (functionStart)
+ {
+ *functionStart = info.FunctionStart;
+ }
if (addrSpace != 0)
{
unw_destroy_addr_space(addrSpace);
@@ -2124,7 +2180,7 @@ exit:
BOOL
PALAPI
-PAL_VirtualUnwindOutOfProc(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextPointers, SIZE_T baseAddress, UnwindReadMemoryCallback readMemoryCallback)
+PAL_VirtualUnwindOutOfProc(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextPointers, PULONG64 functionStart, SIZE_T baseAddress, UnwindReadMemoryCallback readMemoryCallback)
{
return FALSE;
}
diff --git a/src/coreclr/pal/src/exception/signal.cpp b/src/coreclr/pal/src/exception/signal.cpp
index 9ab675c8df6..14dc01dca6a 100644
--- a/src/coreclr/pal/src/exception/signal.cpp
+++ b/src/coreclr/pal/src/exception/signal.cpp
@@ -376,7 +376,7 @@ static void invoke_previous_action(struct sigaction* action, int code, siginfo_t
if (signalRestarts)
{
// This signal mustn't be ignored because it will be restarted.
- PROCAbort();
+ PROCAbort(code);
}
return;
}
@@ -391,7 +391,7 @@ static void invoke_previous_action(struct sigaction* action, int code, siginfo_t
{
// We can't invoke the original handler because returning from the
// handler doesn't restart the exception.
- PROCAbort();
+ PROCAbort(code);
}
}
else
@@ -403,7 +403,8 @@ static void invoke_previous_action(struct sigaction* action, int code, siginfo_t
}
PROCNotifyProcessShutdown(IsRunningOnAlternateStack(context));
- PROCCreateCrashDumpIfEnabled();
+
+ PROCCreateCrashDumpIfEnabled(code);
}
/*++
@@ -575,13 +576,13 @@ static void sigsegv_handler(int code, siginfo_t *siginfo, void *context)
if (SwitchStackAndExecuteHandler(code | StackOverflowFlag, siginfo, context, (size_t)handlerStackTop))
{
- PROCAbort();
+ PROCAbort(SIGSEGV);
}
}
else
{
(void)!write(STDERR_FILENO, StackOverflowMessage, sizeof(StackOverflowMessage) - 1);
- PROCAbort();
+ PROCAbort(SIGSEGV);
}
}
diff --git a/src/coreclr/pal/src/include/pal/process.h b/src/coreclr/pal/src/include/pal/process.h
index 575aa49caac..b1de472ad42 100644
--- a/src/coreclr/pal/src/include/pal/process.h
+++ b/src/coreclr/pal/src/include/pal/process.h
@@ -149,10 +149,13 @@ Function:
Aborts the process after calling the shutdown cleanup handler. This function
should be called instead of calling abort() directly.
+Parameters:
+ signal - POSIX signal number
+
Does not return
--*/
PAL_NORETURN
-VOID PROCAbort();
+VOID PROCAbort(int signal = SIGABRT);
/*++
Function:
@@ -172,9 +175,12 @@ Function:
Creates crash dump of the process (if enabled). Can be
called from the unhandled native exception handler.
+Parameters:
+ signal - POSIX signal number
+
(no return value)
--*/
-VOID PROCCreateCrashDumpIfEnabled();
+VOID PROCCreateCrashDumpIfEnabled(int signal);
/*++
Function:
diff --git a/src/coreclr/pal/src/thread/process.cpp b/src/coreclr/pal/src/thread/process.cpp
index 54e08b7abd9..0ae3f2eecaf 100644
--- a/src/coreclr/pal/src/thread/process.cpp
+++ b/src/coreclr/pal/src/thread/process.cpp
@@ -61,6 +61,7 @@ SET_DEFAULT_DEBUG_CHANNEL(PROCESS); // some headers have code with asserts, so d
#include <stdint.h>
#include <dlfcn.h>
#include <limits.h>
+#include <vector>
#ifdef __linux__
#include <sys/syscall.h> // __NR_membarrier
@@ -232,7 +233,7 @@ static_assert_no_msg(CLR_SEM_MAX_NAMELEN <= MAX_PATH);
Volatile<PSHUTDOWN_CALLBACK> g_shutdownCallback = nullptr;
// Crash dump generating program arguments. Initialized in PROCAbortInitialize().
-char* g_argvCreateDump[8] = { nullptr };
+std::vector<const char*> g_argvCreateDump;
//
// Key used for associating CPalThread's with the underlying pthread
@@ -1334,9 +1335,10 @@ static BOOL PROCEndProcess(HANDLE hProcess, UINT uExitCode, BOOL bTerminateUncon
{
// abort() has the semantics that
// (1) it doesn't run atexit handlers
- // (2) can invoke CrashReporter or produce a coredump,
- // which is appropriate for TerminateProcess calls
- PROCAbort();
+ // (2) can invoke CrashReporter or produce a coredump, which is appropriate for TerminateProcess calls
+ // TerminationRequestHandlingRoutine in synchmanager.cpp sets the exit code to this special value. The
+ // Watson analyzer needs to know that the process was terminated with a SIGTERM.
+ PROCAbort(uExitCode == (128 + SIGTERM) ? SIGTERM : SIGABRT);
}
else
{
@@ -3085,6 +3087,28 @@ PROCNotifyProcessShutdownDestructor()
}
/*++
+Function:
+ PROCFormatInt
+
+ Helper function to format an ULONG32 as a string.
+
+--*/
+char*
+PROCFormatInt(ULONG32 value)
+{
+ char* buffer = (char*)InternalMalloc(128);
+ if (buffer != nullptr)
+ {
+ if (sprintf_s(buffer, 128, "%d", value) == -1)
+ {
+ free(buffer);
+ buffer = nullptr;
+ }
+ }
+ return buffer;
+}
+
+/*++
Function
PROCBuildCreateDumpCommandLine
@@ -3097,12 +3121,13 @@ Return
--*/
BOOL
PROCBuildCreateDumpCommandLine(
- const char** argv,
+ std::vector<const char*>& argv,
char** pprogram,
char** ppidarg,
char* dumpName,
char* dumpType,
- BOOL diag)
+ BOOL diag,
+ BOOL crashReport)
{
if (g_szCoreCLRPath == nullptr)
{
@@ -3132,50 +3157,51 @@ PROCBuildCreateDumpCommandLine(
{
return FALSE;
}
- char* pidarg = *ppidarg = (char*)InternalMalloc(128);
- if (pidarg == nullptr)
+ *ppidarg = PROCFormatInt(gPID);
+ if (*ppidarg == nullptr)
{
return FALSE;
}
- if (sprintf_s(pidarg, 128, "%d", gPID) == -1)
- {
- return FALSE;
- }
- *argv++ = program;
+ argv.push_back(program);
if (dumpName != nullptr)
{
- *argv++ = "--name";
- *argv++ = dumpName;
+ argv.push_back("--name");
+ argv.push_back(dumpName);
}
if (dumpType != nullptr)
{
if (strcmp(dumpType, "1") == 0)
{
- *argv++ = "--normal";
+ argv.push_back("--normal");
}
else if (strcmp(dumpType, "2") == 0)
{
- *argv++ = "--withheap";
+ argv.push_back("--withheap");
}
else if (strcmp(dumpType, "3") == 0)
{
- *argv++ = "--triage";
+ argv.push_back("--triage");
}
else if (strcmp(dumpType, "4") == 0)
{
- *argv++ = "--full";
+ argv.push_back("--full");
}
}
if (diag)
{
- *argv++ = "--diag";
+ argv.push_back("--diag");
+ }
+
+ if (crashReport)
+ {
+ argv.push_back("--crashreport");
}
- *argv++ = pidarg;
- *argv = nullptr;
+ argv.push_back(*ppidarg);
+ argv.push_back(nullptr);
return TRUE;
}
@@ -3190,7 +3216,7 @@ Function:
(no return value)
--*/
BOOL
-PROCCreateCrashDump(char** argv)
+PROCCreateCrashDump(std::vector<const char*>& argv)
{
// Fork the core dump child process.
pid_t childpid = fork();
@@ -3204,7 +3230,7 @@ PROCCreateCrashDump(char** argv)
else if (childpid == 0)
{
// Child process
- if (execve(argv[0], argv, palEnvironment) == -1)
+ if (execve(argv[0], (char**)argv.data(), palEnvironment) == -1)
{
ERROR("PROCCreateCrashDump: execve() FAILED %d (%s)\n", errno, strerror(errno));
return false;
@@ -3258,10 +3284,12 @@ PROCAbortInitialize()
char* dumpType = getenv("COMPlus_DbgMiniDumpType");
char* diagStr = getenv("COMPlus_CreateDumpDiagnostics");
BOOL diag = diagStr != nullptr && strcmp(diagStr, "1") == 0;
+ char* crashReportStr = getenv("COMPlus_EnableCrashReport");
+ BOOL crashReport = crashReportStr != nullptr && strcmp(crashReportStr, "1") == 0;
char* program = nullptr;
char* pidarg = nullptr;
- if (!PROCBuildCreateDumpCommandLine((const char **)g_argvCreateDump, &program, &pidarg, dumpName, dumpType, diag))
+ if (!PROCBuildCreateDumpCommandLine(g_argvCreateDump, &program, &pidarg, dumpName, dumpType, diag, crashReport))
{
return FALSE;
}
@@ -3296,7 +3324,7 @@ PAL_GenerateCoreDump(
INT dumpType,
BOOL diag)
{
- char* argvCreateDump[8] = { nullptr };
+ std::vector<const char*> argvCreateDump;
char dumpTypeStr[16];
if (dumpType < 1 || dumpType > 4)
@@ -3313,7 +3341,7 @@ PAL_GenerateCoreDump(
}
char* program = nullptr;
char* pidarg = nullptr;
- BOOL result = PROCBuildCreateDumpCommandLine((const char **)argvCreateDump, &program, &pidarg, (char*)dumpName, dumpTypeStr, diag);
+ BOOL result = PROCBuildCreateDumpCommandLine(argvCreateDump, &program, &pidarg, (char*)dumpName, dumpTypeStr, diag, false);
if (result)
{
result = PROCCreateCrashDump(argvCreateDump);
@@ -3330,15 +3358,48 @@ Function:
Creates crash dump of the process (if enabled). Can be
called from the unhandled native exception handler.
+Parameters:
+ signal - POSIX signal number
+
(no return value)
--*/
VOID
-PROCCreateCrashDumpIfEnabled()
+PROCCreateCrashDumpIfEnabled(int signal)
{
// If enabled, launch the create minidump utility and wait until it completes
- if (g_argvCreateDump[0] != nullptr)
+ if (!g_argvCreateDump.empty())
{
- PROCCreateCrashDump(g_argvCreateDump);
+ std::vector<const char*> argv(g_argvCreateDump);
+ char* signalArg = nullptr;
+ char* crashThreadArg = nullptr;
+
+ if (signal != 0)
+ {
+ // Remove the terminating nullptr
+ argv.pop_back();
+
+ // Add the Windows exception code to the command line
+ signalArg = PROCFormatInt(signal);
+ if (signalArg != nullptr)
+ {
+ argv.push_back("--signal");
+ argv.push_back(signalArg);
+ }
+
+ // Add the current thread id to the command line. This function is always called on the crashing thread.
+ crashThreadArg = PROCFormatInt(THREADSilentGetCurrentThreadId());
+ if (crashThreadArg != nullptr)
+ {
+ argv.push_back("--crashthread");
+ argv.push_back(crashThreadArg);
+ }
+ argv.push_back(nullptr);
+ }
+
+ PROCCreateCrashDump(argv);
+
+ free(signalArg);
+ free(crashThreadArg);
}
}
@@ -3349,16 +3410,19 @@ Function:
Aborts the process after calling the shutdown cleanup handler. This function
should be called instead of calling abort() directly.
+Parameters:
+ signal - POSIX signal number
+
Does not return
--*/
PAL_NORETURN
VOID
-PROCAbort()
+PROCAbort(int signal)
{
// Do any shutdown cleanup before aborting or creating a core dump
PROCNotifyProcessShutdown();
- PROCCreateCrashDumpIfEnabled();
+ PROCCreateCrashDumpIfEnabled(signal);
// Restore the SIGABORT handler to prevent recursion
SEHCleanupAbort();