else(CLR_CMAKE_HOST_WIN32)
+ if(NOT DEFINED ENV{ROOTFS_DIR})
+ include_directories(SYSTEM /usr/local/include)
+ elseif (CLR_CMAKE_TARGET_FREEBSD)
+ include_directories(SYSTEM $ENV{ROOTFS_DIR}/usr/local/include)
+ endif()
+
include(configure.cmake)
# Set the RPATH of createdump so that it can find dependencies without needing to set LD_LIBRARY_PATH
datatarget.cpp
dumpwriter.cpp
crashreportwriter.cpp
+ ${CLR_SRC_NATIVE_DIR}/minipal/utf8.c
)
if(CLR_CMAKE_HOST_OSX)
dumpwritermacho.cpp
${CREATEDUMP_SOURCES}
)
- add_executable_clr(createdump
- main.cpp
- )
else()
add_library_clr(createdump_static
STATIC
dumpwriterelf.cpp
${CREATEDUMP_SOURCES}
)
+endif(CLR_CMAKE_HOST_OSX)
+
add_executable_clr(createdump
main.cpp
- ${PAL_REDEFINES_FILE}
+ createdumppal.cpp
)
- add_dependencies(createdump pal_redefines_file)
-endif(CLR_CMAKE_HOST_OSX)
target_link_libraries(createdump
PRIVATE
createdump_static
corguids
dbgutil
- # share the PAL in the dac module
- mscordaccore
dl
)
- add_dependencies(createdump mscordaccore)
-
endif(CLR_CMAKE_HOST_WIN32)
install_clr(TARGETS createdump DESTINATIONS . sharedFramework COMPONENT runtime)
#pragma once
#cmakedefine HAVE_PROCESS_VM_READV
+#cmakedefine01 HAVE_CLOCK_GETTIME_NSEC_NP
+#cmakedefine01 HAVE_CLOCK_MONOTONIC
check_function_exists(process_vm_readv HAVE_PROCESS_VM_READV)
+check_symbol_exists(
+ clock_gettime_nsec_np
+ time.h
+ HAVE_CLOCK_GETTIME_NSEC_NP)
+
+check_cxx_source_runs("
+#include <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+
+int main()
+{
+ int ret;
+ struct timespec ts;
+ ret = clock_gettime(CLOCK_MONOTONIC, &ts);
+
+ exit(ret);
+}" HAVE_CLOCK_MONOTONIC)
+
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
bool
CrashInfo::InitializeDAC(DumpType dumpType)
{
- // Don't attempt to load the DAC if the app model doesn't support it by default. The default for single-file is a
- // full dump, but if the dump type requested is a mini, triage or heap and the DAC is side-by-side to the single-file
- // application the core dump will be generated.
- if (dumpType == DumpType::Full && (m_appModel == AppModelType::SingleFile || m_appModel == AppModelType::NativeAOT))
+ // Don't attempt to load the DAC if the app model doesn't support it by default. The default for single-file is
+ // a full dump, but if the dump type requested is a mini, triage or heap and the DAC is next to the single-file
+ // application the core dump will be generated. For NativeAOT, there is currently no DAC available so never
+ // attempt to load it.
+ if ((dumpType == DumpType::Full && m_appModel == AppModelType::SingleFile) || m_appModel == AppModelType::NativeAOT)
{
return true;
}
bool
CrashInfo::UnwindAllThreads()
{
- TRACE("UnwindAllThreads: STARTED (%d)\n", m_dataTargetPagesAdded);
- ReleaseHolder<ISOSDacInterface> pSos = nullptr;
- if (m_pClrDataProcess != nullptr) {
- m_pClrDataProcess->QueryInterface(__uuidof(ISOSDacInterface), (void**)&pSos);
- }
- // For each native and managed thread
- for (ThreadInfo* thread : m_threads)
+ // Don't unwind any threads if Native AOT since there isn't a DAC to get the remote
+ // unwinder support and they are full dumps.
+ if (m_appModel != AppModelType::NativeAOT)
{
- if (!thread->UnwindThread(m_pClrDataProcess, pSos)) {
- return false;
+ TRACE("UnwindAllThreads: STARTED (%d)\n", m_dataTargetPagesAdded);
+ ReleaseHolder<ISOSDacInterface> pSos = nullptr;
+ if (m_pClrDataProcess != nullptr) {
+ m_pClrDataProcess->QueryInterface(__uuidof(ISOSDacInterface), (void**)&pSos);
+ }
+ // For each native and managed thread
+ for (ThreadInfo* thread : m_threads)
+ {
+ if (!thread->UnwindThread(m_pClrDataProcess, pSos)) {
+ return false;
+ }
}
+ TRACE("UnwindAllThreads: FINISHED (%d)\n", m_dataTargetPagesAdded);
}
- TRACE("UnwindAllThreads: FINISHED (%d)\n", m_dataTargetPagesAdded);
return true;
}
ArrayHolder<char> buffer = new char[MAX_LONGPATH + 1];
va_list args;
va_start(args, format);
- int result = vsprintf_s(buffer, MAX_LONGPATH, format, args);
+ int result = vsnprintf(buffer, MAX_LONGPATH, format, args);
va_end(args);
- return result > 0 ? std::string(buffer) : std::string();
+ return result > 0 && result < MAX_LONGPATH ? std::string(buffer) : std::string();
}
//
ConvertString(const WCHAR* str)
{
if (str == nullptr)
- return{};
+ return { };
- int len = WideCharToMultiByte(CP_UTF8, 0, str, -1, nullptr, 0, nullptr, nullptr);
+ size_t cch = u16_strlen(str) + 1;
+ int len = minipal_get_length_utf16_to_utf8((CHAR16_T*)str, cch, 0);
if (len == 0)
- return{};
+ return { };
ArrayHolder<char> buffer = new char[len + 1];
- WideCharToMultiByte(CP_UTF8, 0, str, -1, buffer, len + 1, nullptr, nullptr);
- return std::string{ buffer };
+ minipal_convert_utf16_to_utf8((CHAR16_T*)str, cch, buffer, len + 1, 0);
+ return std::string { buffer };
}
//
// Round to page boundary
start = start & PAGE_MASK;
- _ASSERTE(start > 0);
+ assert(start > 0);
// Round up to page boundary
end = (end + (PAGE_SIZE - 1)) & PAGE_MASK;
- _ASSERTE(end > 0);
+ assert(end > 0);
// Add module memory region if not already on the list
MemoryRegion newModule(regionFlags, start, end, offset, module.Name());
CrashInfo::Initialize()
{
char memPath[128];
- _snprintf_s(memPath, sizeof(memPath), sizeof(memPath), "/proc/%u/mem", m_pid);
+ int chars = snprintf(memPath, sizeof(memPath), "/proc/%u/mem", m_pid);
+ if (chars <= 0 || (size_t)chars >= sizeof(memPath))
+ {
+ printf_error("snprintf failed building /proc/<pid>/mem name\n");
+ return false;
+ }
m_fdMem = open(memPath, O_RDONLY);
if (m_fdMem == -1)
{
TRACE("DbgDisablePagemapUse detected - pagemap file checking is enabled\n");
char pagemapPath[128];
- _snprintf_s(pagemapPath, sizeof(pagemapPath), sizeof(pagemapPath), "/proc/%u/pagemap", m_pid);
+ chars = snprintf(pagemapPath, sizeof(pagemapPath), "/proc/%u/pagemap", m_pid);
+ if (chars <= 0 || (size_t)chars >= sizeof(pagemapPath))
+ {
+ printf_error("snprintf failed building /proc/<pid>/pagemap name\n");
+ return false;
+ }
m_fdPagemap = open(pagemapPath, O_RDONLY);
if (m_fdPagemap == -1)
{
CrashInfo::EnumerateAndSuspendThreads()
{
char taskPath[128];
- _snprintf_s(taskPath, sizeof(taskPath), sizeof(taskPath), "/proc/%u/task", m_pid);
+ int chars = snprintf(taskPath, sizeof(taskPath), "/proc/%u/task", m_pid);
+ if (chars <= 0 || (size_t)chars >= sizeof(taskPath))
+ {
+ printf_error("snprintf failed building /proc/<pid>/task\n");
+ return false;
+ }
DIR* taskDir = opendir(taskPath);
if (taskDir == nullptr)
CrashInfo::GetAuxvEntries()
{
char auxvPath[128];
- _snprintf_s(auxvPath, sizeof(auxvPath), sizeof(auxvPath), "/proc/%u/auxv", m_pid);
-
+ int chars = snprintf(auxvPath, sizeof(auxvPath), "/proc/%u/auxv", m_pid);
+ if (chars <= 0 || (size_t)chars >= sizeof(auxvPath))
+ {
+ printf_error("snprintf failed building /proc/<pid>/auxv\n");
+ return false;
+ }
int fd = open(auxvPath, O_RDONLY, 0);
if (fd == -1)
{
// Making something like: /proc/123/maps
char mapPath[128];
- int chars = _snprintf_s(mapPath, sizeof(mapPath), sizeof(mapPath), "/proc/%u/maps", m_pid);
- assert(chars > 0 && (size_t)chars <= sizeof(mapPath));
-
+ int chars = snprintf(mapPath, sizeof(mapPath), "/proc/%u/maps", m_pid);
+ if (chars <= 0 || (size_t)chars >= sizeof(mapPath))
+ {
+ printf_error("snprintf failed building /proc/<pid>/maps\n");
+ return false;
+ }
FILE* mapsFile = fopen(mapPath, "r");
if (mapsFile == nullptr)
{
TRACE("VisitProgramHeader: ehFrameHdrStart %016llx ehFrameHdrSize %08llx\n", ehFrameHdrStart, ehFrameHdrSize);
InsertMemoryRegion(ehFrameHdrStart, ehFrameHdrSize);
- ULONG64 ehFrameStart;
- ULONG64 ehFrameSize;
- if (PAL_GetUnwindInfoSize(baseAddress, ehFrameHdrStart, ReadMemoryAdapter, &ehFrameStart, &ehFrameSize))
+ if (m_appModel != AppModelType::NativeAOT)
{
- TRACE("VisitProgramHeader: ehFrameStart %016llx ehFrameSize %08llx\n", ehFrameStart, ehFrameSize);
- if (ehFrameStart != 0 && ehFrameSize != 0)
+ ULONG64 ehFrameStart;
+ ULONG64 ehFrameSize;
+ if (PAL_GetUnwindInfoSize(baseAddress, ehFrameHdrStart, ReadMemoryAdapter, &ehFrameStart, &ehFrameSize))
{
- InsertMemoryRegion(ehFrameStart, ehFrameSize);
+ TRACE("VisitProgramHeader: ehFrameStart %016llx ehFrameSize %08llx\n", ehFrameStart, ehFrameSize);
+ if (ehFrameStart != 0 && ehFrameSize != 0)
+ {
+ InsertMemoryRegion(ehFrameStart, ehFrameSize);
+ }
+ }
+ else
+ {
+ TRACE("VisitProgramHeader: PAL_GetUnwindInfoSize FAILED\n");
}
- }
- else
- {
- TRACE("VisitProgramHeader: PAL_GetUnwindInfoSize FAILED\n");
}
}
break;
GetStatus(pid_t pid, pid_t* ppid, pid_t* tgid, std::string* name)
{
char statusPath[128];
- _snprintf_s(statusPath, sizeof(statusPath), sizeof(statusPath), "/proc/%d/status", pid);
+ int chars = snprintf(statusPath, sizeof(statusPath), "/proc/%d/status", pid);
+ if (chars <= 0 || (size_t)chars >= sizeof(statusPath))
+ {
+ printf_error("snprintf failed building /proc/<pid>/status\n");
+ return false;
+ }
FILE *statusFile = fopen(statusPath, "r");
if (statusFile == nullptr)
CrashReportWriter::WriteValue32(const char* key, uint32_t value)
{
char buffer[16];
- _snprintf_s(buffer, sizeof(buffer), sizeof(buffer), "0x%x", value);
+ snprintf(buffer, sizeof(buffer), "0x%x", value);
WriteValue(key, buffer);
}
CrashReportWriter::WriteValue64(const char* key, uint64_t value)
{
char buffer[32];
- _snprintf_s(buffer, sizeof(buffer), sizeof(buffer), "0x%" PRIx64, value);
+ snprintf(buffer, sizeof(buffer), "0x%" PRIx64, value);
WriteValue(key, buffer);
}
#include <arrayholder.h>
#include <releaseholder.h>
#ifdef HOST_UNIX
+#include <minipal/utf8.h>
+#include <dn-u16.h>
#include <dumpcommon.h>
#include <clrconfignocache.h>
#include <unistd.h>
"--crashreportonly - write crash report file only (no dump).\n"
"--crashthread <id> - the thread id of the crashing thread.\n"
"--signal <code> - the signal code of the crash.\n"
-"--singlefile - enable single-file app check.\n"
+"--singlefile - single-file app model.\n"
+"--nativeaot - native AOT app model.\n"
#endif
;
{
options.AppModel = AppModelType::SingleFile;
}
+ else if (strcmp(*argv, "--nativeaot") == 0)
+ {
+ options.AppModel = AppModelType::NativeAOT;
+ }
else if (strcmp(*argv, "--code") == 0)
{
options.SignalCode = atoi(*++argv);
{
if (::GetTempPathA(MAX_LONGPATH, tmpPath) == 0)
{
- //printf_error("GetTempPath failed %s", GetLastErrorString().c_str());
printf_error("GetTempPath failed\n");
- return ::GetLastError();
+ return -1;
}
exitCode = strcat_s(tmpPath, MAX_LONGPATH, DEFAULT_DUMP_TEMPLATE);
if (exitCode != 0)
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#include "createdump.h"
+#include <time.h>
+#include <sys/time.h>
+
+#define INITGUID
+#include <guiddef.h>
+
+DEFINE_GUID(IID_IUnknown, 0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
+
+#if defined(__linux__)
+#define PAL_FUNCTION_PREFIX "DAC_"
+#else
+#define PAL_FUNCTION_PREFIX
+#endif
+
+typedef int (*PFN_PAL_InitializeDLL)();
+typedef void (*PFN_PAL_TerminateEx)(int);
+
+typedef BOOL (*PFN_PAL_VirtualUnwindOutOfProc)(
+ CONTEXT *context,
+ KNONVOLATILE_CONTEXT_POINTERS *contextPointers,
+ PULONG64 functionStart,
+ SIZE_T baseAddress,
+ UnwindReadMemoryCallback readMemoryCallback);
+
+typedef BOOL (*PFN_PAL_GetUnwindInfoSize)(
+ SIZE_T baseAddress,
+ ULONG64 ehFrameHdrAddr,
+ UnwindReadMemoryCallback readMemoryCallback,
+ PULONG64 ehFrameStart,
+ PULONG64 ehFrameSize);
+
+bool g_initialized = false;
+PFN_PAL_InitializeDLL g_PAL_InitializeDLL = nullptr;
+PFN_PAL_TerminateEx g_PAL_TerminateEx = nullptr;
+PFN_PAL_VirtualUnwindOutOfProc g_PAL_VirtualUnwindOutOfProc = nullptr;
+PFN_PAL_GetUnwindInfoSize g_PAL_GetUnwindInfoSize = nullptr;
+
+bool
+InitializePAL()
+{
+ if (g_initialized)
+ {
+ return true;
+ }
+ g_initialized = true;
+
+ // Get createdump's path and load the DAC next to it.
+ Dl_info info;
+ if (dladdr((PVOID)&InitializePAL, &info) == 0)
+ {
+ printf_error("InitializePAL: dladdr(&InitializePAL) FAILED %s\n", dlerror());
+ return false;
+ }
+ std::string dacPath;
+ dacPath.append(info.dli_fname);
+ dacPath = GetDirectory(dacPath);
+ dacPath.append(MAKEDLLNAME_A("mscordaccore"));
+
+ // Load the DAC next to createdump
+ void* dacModule = dlopen(dacPath.c_str(), RTLD_LAZY);
+ if (dacModule == nullptr)
+ {
+ printf_error("InitializePAL: dlopen(%s) FAILED %s\n", dacPath.c_str(), dlerror());
+ return false;
+ }
+
+ // Get the PAL entry points needed by createdump
+ g_PAL_InitializeDLL = (PFN_PAL_InitializeDLL)dlsym(dacModule, PAL_FUNCTION_PREFIX "PAL_InitializeDLL");
+ if (g_PAL_InitializeDLL == nullptr)
+ {
+ printf_error("InitializePAL: dlsym(PAL_InitializeDLL) FAILED %s\n", dlerror());
+ return false;
+ }
+ if (g_PAL_InitializeDLL() != 0)
+ {
+ printf_error("InitializePAL: PAL initialization FAILED\n");
+ return false;
+ }
+ g_PAL_TerminateEx = (PFN_PAL_TerminateEx)dlsym(dacModule, PAL_FUNCTION_PREFIX "PAL_TerminateEx");
+ g_PAL_VirtualUnwindOutOfProc = (PFN_PAL_VirtualUnwindOutOfProc)dlsym(dacModule, PAL_FUNCTION_PREFIX "PAL_VirtualUnwindOutOfProc");
+ g_PAL_GetUnwindInfoSize = (PFN_PAL_GetUnwindInfoSize)dlsym(dacModule, PAL_FUNCTION_PREFIX "PAL_GetUnwindInfoSize");
+ return true;
+}
+
+void
+UninitializePAL(
+ int exitCode)
+{
+ if (g_PAL_TerminateEx != nullptr)
+ {
+ g_PAL_TerminateEx(exitCode);
+ }
+}
+
+#define tccSecondsToNanoSeconds 1000000000 // 10^9
+
+BOOL
+PALAPI
+QueryPerformanceCounter(
+ OUT LARGE_INTEGER* lpPerformanceCount)
+{
+#if HAVE_CLOCK_GETTIME_NSEC_NP
+ lpPerformanceCount->QuadPart = (LONGLONG)clock_gettime_nsec_np(CLOCK_UPTIME_RAW);
+#elif HAVE_CLOCK_MONOTONIC
+ struct timespec ts;
+ int result = clock_gettime(CLOCK_MONOTONIC, &ts);
+ if (result != 0)
+ {
+ return TRUE;
+ }
+ else
+ {
+ lpPerformanceCount->QuadPart = ((LONGLONG)(ts.tv_sec) * (LONGLONG)(tccSecondsToNanoSeconds)) + (LONGLONG)(ts.tv_nsec);
+ }
+#else
+ #error "The createdump requires either mach_absolute_time() or clock_gettime(CLOCK_MONOTONIC) to be supported."
+#endif
+ return TRUE;
+}
+
+BOOL
+PALAPI
+QueryPerformanceFrequency(
+ OUT LARGE_INTEGER* lpFrequency)
+{
+#if HAVE_CLOCK_GETTIME_NSEC_NP
+ lpFrequency->QuadPart = (LONGLONG)(tccSecondsToNanoSeconds);
+#elif HAVE_CLOCK_MONOTONIC
+ // clock_gettime() returns a result in terms of nanoseconds rather than a count. This
+ // means that we need to either always scale the result by the actual resolution (to
+ // get a count) or we need to say the resolution is in terms of nanoseconds. We prefer
+ // the latter since it allows the highest throughput and should minimize error propagated
+ // to the user.
+ lpFrequency->QuadPart = (LONGLONG)(tccSecondsToNanoSeconds);
+#else
+ #error "The createdump requires either mach_absolute_time() or clock_gettime(CLOCK_MONOTONIC) to be supported."
+#endif
+ return TRUE;
+}
+
+#define TEMP_DIRECTORY_PATH "/tmp/"
+
+DWORD
+PALAPI
+GetTempPathA(
+ IN DWORD nBufferLength,
+ OUT LPSTR lpBuffer)
+{
+ DWORD dwPathLen = 0;
+ const char *tempDir = getenv("TMPDIR");
+ if (tempDir == nullptr)
+ {
+ tempDir = TEMP_DIRECTORY_PATH;
+ }
+ size_t tempDirLen = strlen(tempDir);
+ if (tempDirLen < nBufferLength)
+ {
+ dwPathLen = tempDirLen;
+ strcpy_s(lpBuffer, nBufferLength, tempDir);
+ }
+ else
+ {
+ // Get the required length
+ dwPathLen = tempDirLen + 1;
+ }
+ return dwPathLen;
+}
+
+BOOL
+PALAPI
+PAL_VirtualUnwindOutOfProc(
+ CONTEXT *context,
+ KNONVOLATILE_CONTEXT_POINTERS *contextPointers,
+ PULONG64 functionStart,
+ SIZE_T baseAddress,
+ UnwindReadMemoryCallback readMemoryCallback)
+{
+ if (!InitializePAL() || g_PAL_VirtualUnwindOutOfProc == nullptr)
+ {
+ return FALSE;
+ }
+ return g_PAL_VirtualUnwindOutOfProc(context, contextPointers, functionStart, baseAddress, readMemoryCallback);
+}
+
+BOOL
+PALAPI
+PAL_GetUnwindInfoSize(
+ SIZE_T baseAddress,
+ ULONG64 ehFrameHdrAddr,
+ UnwindReadMemoryCallback readMemoryCallback,
+ PULONG64 ehFrameStart,
+ PULONG64 ehFrameSize)
+{
+ if (!InitializePAL() || g_PAL_GetUnwindInfoSize == nullptr)
+ {
+ return FALSE;
+ }
+ return g_PAL_GetUnwindInfoSize(baseAddress, ehFrameHdrAddr, readMemoryCallback, ehFrameStart, ehFrameSize);
+}
+
+//
+// Used in pal\inc\rt\safecrt.h's _invalid_parameter handler
+//
+
+VOID
+PALAPI
+RaiseException(
+ IN DWORD dwExceptionCode,
+ IN DWORD dwExceptionFlags,
+ IN DWORD nNumberOfArguments,
+ IN CONST ULONG_PTR* lpArguments)
+{
+ throw;
+}
+
+size_t u16_strlen(const WCHAR* str)
+{
+ size_t nChar = 0;
+ while (*str++)
+ nChar++;
+ return nChar;
+}
+
+//
+// Used by _ASSERTE
+//
+
+#ifdef _DEBUG
+
+PAL_FILE *
+__cdecl
+PAL_get_stderr(int caller)
+{
+ return (PAL_FILE*)stderr;
+}
+
+int
+__cdecl
+PAL_fprintf(PAL_FILE* stream, const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ int result = vfprintf((FILE*)stream, format, args);
+ fflush((FILE*)stream);
+ va_end(args);
+ return result;
+}
+
+DWORD
+PALAPI
+GetCurrentProcessId()
+{
+ return getpid();
+}
+
+VOID
+PALAPI
+DebugBreak()
+{
+ abort();
+}
+
+#endif // DEBUG
+
goto exit;
}
+ if (options.DumpType != DumpType::Full && options.AppModel == AppModelType::NativeAOT)
+ {
+ printf_error("The app model only supports full dump generation\n");
+ goto exit;
+ }
+
// Initialize the crash info
if (!crashInfo->Initialize())
{
*baseAddress = 0;
char tempModuleName[MAX_PATH];
- int length = WideCharToMultiByte(CP_ACP, 0, moduleName, -1, tempModuleName, sizeof(tempModuleName), NULL, NULL);
+ size_t cch = u16_strlen(moduleName) + 1;
+ int length = minipal_convert_utf16_to_utf8((CHAR16_T*)moduleName, cch, tempModuleName, sizeof(tempModuleName), 0);
if (length > 0)
{
*baseAddress = m_crashInfo.GetBaseAddressFromName(tempModuleName);
}
-
return *baseAddress != 0 ? S_OK : E_FAIL;
}
#include "createdump.h"
extern int createdump_main(const int argc, const char* argv[]);
+extern void UninitializePAL(int exitCode);
#if defined(HOST_ARM64)
// Flag to check if atomics feature is available on
//
int __cdecl main(const int argc, const char* argv[])
{
- int exitCode = 0;
+ int exitCode = createdump_main(argc, argv);
#ifdef HOST_UNIX
- exitCode = PAL_InitializeDLL();
- if (exitCode != 0)
- {
- printf_error("PAL initialization FAILED %d\n", exitCode);
- return exitCode;
- }
-#endif
- exitCode = createdump_main(argc, argv);
-#ifdef HOST_UNIX
- PAL_TerminateEx(exitCode);
+ UninitializePAL(exitCode);
#endif
return exitCode;
}
context->Fcsr = m_fpRegisters.fpscr;
}
#elif defined(__riscv)
- _ASSERTE(!"TODO RISCV64 NYI");
+ assert(!"TODO RISCV64 NYI");
#else
#error Platform not supported
#endif