Remove createdump's DAC dependency for the PAL for NativeAOT (#88802)
authorMike McLaughlin <mikem@microsoft.com>
Tue, 18 Jul 2023 02:05:53 +0000 (19:05 -0700)
committerGitHub <noreply@github.com>
Tue, 18 Jul 2023 02:05:53 +0000 (19:05 -0700)
* Remove createdump's DAC dependency for the PAL for NativeAOT

* Code review feedback - use utf16 mini pal functions

* Fix OSX build break

* Code review feedback

14 files changed:
src/coreclr/debug/createdump/CMakeLists.txt
src/coreclr/debug/createdump/config.h.in
src/coreclr/debug/createdump/configure.cmake
src/coreclr/debug/createdump/crashinfo.cpp
src/coreclr/debug/createdump/crashinfomac.cpp
src/coreclr/debug/createdump/crashinfounix.cpp
src/coreclr/debug/createdump/crashreportwriter.cpp
src/coreclr/debug/createdump/createdump.h
src/coreclr/debug/createdump/createdumpmain.cpp
src/coreclr/debug/createdump/createdumppal.cpp [new file with mode: 0644]
src/coreclr/debug/createdump/createdumpunix.cpp
src/coreclr/debug/createdump/datatarget.cpp
src/coreclr/debug/createdump/main.cpp
src/coreclr/debug/createdump/threadinfounix.cpp

index 282412f..c108586 100644 (file)
@@ -37,6 +37,12 @@ if(CLR_CMAKE_HOST_WIN32)
 
 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
@@ -64,6 +70,7 @@ else(CLR_CMAKE_HOST_WIN32)
         datatarget.cpp
         dumpwriter.cpp
         crashreportwriter.cpp
+        ${CLR_SRC_NATIVE_DIR}/minipal/utf8.c
     )
 
 if(CLR_CMAKE_HOST_OSX)
@@ -74,9 +81,6 @@ if(CLR_CMAKE_HOST_OSX)
         dumpwritermacho.cpp
         ${CREATEDUMP_SOURCES}
     )
-    add_executable_clr(createdump
-        main.cpp
-    )
 else()
     add_library_clr(createdump_static
         STATIC
@@ -85,25 +89,21 @@ else()
         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)
index ee8701b..792d8a5 100644 (file)
@@ -4,3 +4,5 @@
 #pragma once
 
 #cmakedefine HAVE_PROCESS_VM_READV
+#cmakedefine01 HAVE_CLOCK_GETTIME_NSEC_NP
+#cmakedefine01 HAVE_CLOCK_MONOTONIC
index 9587b3f..4ba6320 100644 (file)
@@ -1,3 +1,22 @@
 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)
index 44294dc..c9bf223 100644 (file)
@@ -280,10 +280,11 @@ GetHResultString(HRESULT hr)
 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;
     }
@@ -483,19 +484,24 @@ CrashInfo::EnumerateManagedModules()
 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;
 }
 
@@ -959,9 +965,9 @@ FormatString(const char* format, ...)
     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();
 }
 
 //
@@ -971,15 +977,16 @@ 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 };
 }
 
 //
index 97477f2..90a31f1 100644 (file)
@@ -288,11 +288,11 @@ void CrashInfo::VisitSegment(MachOModule& module, const segment_command_64& segm
 
             // 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());
index d4b003a..70b2ddb 100644 (file)
@@ -17,7 +17,12 @@ bool
 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)
@@ -42,7 +47,12 @@ CrashInfo::Initialize()
     {
         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)
         {
@@ -95,7 +105,12 @@ bool
 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)
@@ -139,8 +154,12 @@ bool
 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)
     {
@@ -195,9 +214,12 @@ CrashInfo::EnumerateMemoryRegions()
 
     // 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)
     {
@@ -401,19 +423,22 @@ CrashInfo::VisitProgramHeader(uint64_t loadbias, uint64_t baseAddress, Phdr* phd
             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;
@@ -489,7 +514,12 @@ bool
 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)
index 77081fa..a092e93 100644 (file)
@@ -376,7 +376,7 @@ void
 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);
 }
 
@@ -384,7 +384,7 @@ void
 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);
 }
 
index 3d796d5..e24fa94 100644 (file)
@@ -53,6 +53,8 @@ typedef int T_CONTEXT;
 #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>
index 503bfec..1046839 100644 (file)
@@ -33,7 +33,8 @@ const char* g_help = "createdump [options]\n"
 "--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
 ;
 
@@ -126,6 +127,10 @@ int createdump_main(const int argc, const char* argv[])
             {
                 options.AppModel = AppModelType::SingleFile;
             }
+            else if (strcmp(*argv, "--nativeaot") == 0)
+            {
+                options.AppModel = AppModelType::NativeAOT;
+            }
             else if (strcmp(*argv, "--code") == 0)
             {
                 options.SignalCode = atoi(*++argv);
@@ -199,9 +204,8 @@ int createdump_main(const int argc, const char* 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)
diff --git a/src/coreclr/debug/createdump/createdumppal.cpp b/src/coreclr/debug/createdump/createdumppal.cpp
new file mode 100644 (file)
index 0000000..4dd7204
--- /dev/null
@@ -0,0 +1,268 @@
+// 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
+
index 0b97a3a..ea6fa5b 100644 (file)
@@ -30,6 +30,12 @@ CreateDump(const CreateDumpOptions& options)
         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())
     {
index 3867553..420300e 100644 (file)
@@ -102,12 +102,12 @@ DumpDataTarget::GetImageBase(
     *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;
 }
 
index 8229472..b322a3c 100644 (file)
@@ -4,6 +4,7 @@
 #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
@@ -16,18 +17,9 @@ bool g_arm64_atomics_present = false;
 //
 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;
 }
index ca75a61..d1683b9 100644 (file)
@@ -246,7 +246,7 @@ ThreadInfo::GetThreadContext(uint32_t flags, CONTEXT* context) const
         context->Fcsr = m_fpRegisters.fpscr;
     }
 #elif defined(__riscv)
-    _ASSERTE(!"TODO RISCV64 NYI");
+    assert(!"TODO RISCV64 NYI");
 #else
 #error Platform not supported
 #endif