Merge pull request #4444 from lateralusX/jlorenss/windows-unwind-info
authorJohan Lorensson <lateralusx.github@gmail.com>
Fri, 10 Mar 2017 10:16:23 +0000 (11:16 +0100)
committerGitHub <noreply@github.com>
Fri, 10 Mar 2017 10:16:23 +0000 (11:16 +0100)
Improve unwind support on Windows x64.

17 files changed:
eglib/winconfig.h
mono/mini/Makefile.am.in
mono/mini/aot-compiler.c
mono/mini/exceptions-amd64.c
mono/mini/mini-amd64.c
mono/mini/mini-amd64.h
mono/mini/mini-runtime.c
mono/mini/mini-unwind.h
mono/mini/mini-windows-dlldac.c [new file with mode: 0644]
mono/mini/mini.c
mono/mini/tramp-amd64-gsharedvt.c
mono/mini/tramp-amd64.c
mono/mini/unwind.c
msvc/libmonodac.vcxproj [new file with mode: 0644]
msvc/libmonodac.vcxproj.filters [new file with mode: 0644]
msvc/mono.sln
winconfig.h

index 238250bba05455b75186c920c11dc70efd3d983d..31bbf89a6a17169c8c7dbb4b30251b09a38cef9f 100755 (executable)
@@ -5,6 +5,32 @@
 #include "cygconfig.h"
 #else
 
+#ifndef HAVE_WINAPI_FAMILY_SUPPORT
+
+#define HAVE_WINAPI_FAMILY_SUPPORT
+
+/* WIN API Family support */
+#include <winapifamily.h>
+
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+       #define HAVE_CLASSIC_WINAPI_SUPPORT 1
+       #define HAVE_UWP_WINAPI_SUPPORT 0
+#elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
+       #define HAVE_CLASSIC_WINAPI_SUPPORT 0
+       #define HAVE_UWP_WINAPI_SUPPORT 1
+#ifndef HAVE_EXTERN_DEFINED_WINAPI_SUPPORT
+       #error Unsupported WINAPI family
+#endif
+#else
+       #define HAVE_CLASSIC_WINAPI_SUPPORT 0
+       #define HAVE_UWP_WINAPI_SUPPORT 0
+#ifndef HAVE_EXTERN_DEFINED_WINAPI_SUPPORT
+       #error Unsupported WINAPI family
+#endif
+#endif
+
+#endif
+
 /* Define to 1 if you have the <dlfcn.h> header file. */
 #define HAVE_DLFCN_H 1
 
 #define VERSION "0.1"
 
 #define HAVE_STRTOK_R 1
-
-#ifndef HAVE_WINAPI_FAMILY_SUPPORT
-
-#define HAVE_WINAPI_FAMILY_SUPPORT
-
-/* WIN API Family support */
-#include <winapifamily.h>
-
-#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
-       #define HAVE_CLASSIC_WINAPI_SUPPORT 1
-       #define HAVE_UWP_WINAPI_SUPPORT 0
-#elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
-       #define HAVE_CLASSIC_WINAPI_SUPPORT 0
-       #define HAVE_UWP_WINAPI_SUPPORT 1
-#ifndef HAVE_EXTERN_DEFINED_WINAPI_SUPPORT
-       #error Unsupported WINAPI family
-#endif
-#else
-       #define HAVE_CLASSIC_WINAPI_SUPPORT 0
-       #define HAVE_UWP_WINAPI_SUPPORT 0
-#ifndef HAVE_EXTERN_DEFINED_WINAPI_SUPPORT
-       #error Unsupported WINAPI family
-#endif
-#endif
-
-#endif
 #endif
index e4a126a7e29cda36597c0944289f8fea5efd5d10..4592dec23c164804b8b72003e49d64372c4aa311 100755 (executable)
@@ -378,7 +378,8 @@ darwin_sources = \
 windows_sources = \
        mini-windows.c \
        mini-windows.h \
-       mini-windows-dllmain.c
+       mini-windows-dllmain.c \
+       mini-windows-dlldac.c
 
 posix_sources = \
        mini-posix.c
index c3ef028789288d800198496a68031222426e2cdf..22dc64f95197ac60691c4a89eac17f793438fc2f 100644 (file)
@@ -8200,7 +8200,7 @@ execute_system (const char * command)
 {
        int status = 0;
 
-#if HOST_WIN32
+#if defined(HOST_WIN32) && defined(HAVE_SYSTEM)
        // We need an extra set of quotes around the whole command to properly handle commands 
        // with spaces since internally the command is called through "cmd /c.
        char * quoted_command = g_strdup_printf ("\"%s\"", command);
index 38c333c466cadf36d6e9b77e9c59bc514decc018..383aea2f447911cd020226c709046309e8159efa 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Authors:
  *   Dietmar Maurer (dietmar@ximian.com)
+ *   Johan Lorensson (lateralusx.github@gmail.com)
  *
  * (C) 2001 Ximian, Inc.
  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
@@ -273,7 +274,12 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot)
                if (AMD64_IS_CALLEE_SAVED_REG (i))
                        amd64_pop_reg (code, i);
 
+#if TARGET_WIN32
+       amd64_lea_membase (code, AMD64_RSP, AMD64_RBP, 0);
+       amd64_pop_reg (code, AMD64_RBP);
+#else
        amd64_leave (code);
+#endif
        amd64_ret (code);
 
        g_assert ((code - start) < kMaxCodeSize);
@@ -375,7 +381,10 @@ get_throw_trampoline (MonoTrampInfo **info, gboolean rethrow, gboolean corlib, g
        dummy_stack_space = 0;
 #endif
 
-       start = code = (guint8 *)mono_global_codeman_reserve (kMaxCodeSize);
+       if (info)
+               start = code = (guint8 *)mono_global_codeman_reserve (kMaxCodeSize + MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE);
+       else
+               start = code = (guint8 *)mono_global_codeman_reserve (kMaxCodeSize);
 
        /* The stack is unaligned on entry */
        stack_size = ALIGN_TO (sizeof (MonoContext) + 64 + dummy_stack_space, MONO_ARCH_FRAME_ALIGNMENT) + 8;
@@ -387,8 +396,10 @@ get_throw_trampoline (MonoTrampInfo **info, gboolean rethrow, gboolean corlib, g
 
        /* Alloc frame */
        amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, stack_size);
-       if (info)
+       if (info) {
                mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, stack_size + 8);
+               mono_add_unwind_op_sp_alloc (unwind_ops, code, start, stack_size);
+       }
 
        /*
         * To hide linux/windows calling convention differences, we pass all arguments on
@@ -455,6 +466,7 @@ get_throw_trampoline (MonoTrampInfo **info, gboolean rethrow, gboolean corlib, g
        mono_arch_flush_icache (start, code - start);
 
        g_assert ((code - start) < kMaxCodeSize);
+       g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE));
 
        mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL);
 
@@ -885,260 +897,878 @@ mono_arch_exceptions_init (void)
        }
 }
 
-#if defined(TARGET_WIN32) && !defined(DISABLE_JIT)
-
-/*
- * The mono_arch_unwindinfo* methods are used to build and add
- * function table info for each emitted method from mono.  On Winx64
- * the seh handler will not be called if the mono methods are not
- * added to the function table.  
- *
- * We should not need to add non-volatile register info to the 
- * table since mono stores that info elsewhere. (Except for the register 
- * used for the fp.)
- */
-
-#define MONO_MAX_UNWIND_CODES 22
-
-typedef union _UNWIND_CODE {
-    struct {
-        guchar CodeOffset;
-        guchar UnwindOp : 4;
-        guchar OpInfo   : 4;
-    };
-    gushort FrameOffset;
-} UNWIND_CODE, *PUNWIND_CODE;
-
-typedef struct _UNWIND_INFO {
-       guchar Version       : 3;
-       guchar Flags         : 5;
-       guchar SizeOfProlog;
-       guchar CountOfCodes;
-       guchar FrameRegister : 4;
-       guchar FrameOffset   : 4;
-       /* custom size for mono allowing for mono allowing for*/
-       /*UWOP_PUSH_NONVOL ebp offset = 21*/
-       /*UWOP_ALLOC_LARGE : requires 2 or 3 offset = 20*/
-       /*UWOP_SET_FPREG : requires 2 offset = 17*/
-       /*UWOP_PUSH_NONVOL offset = 15-0*/
-       UNWIND_CODE UnwindCode[MONO_MAX_UNWIND_CODES]; 
-
-/*     UNWIND_CODE MoreUnwindCode[((CountOfCodes + 1) & ~1) - 1];
- *     union {
- *         OPTIONAL ULONG ExceptionHandler;
- *         OPTIONAL ULONG FunctionEntry;
- *     };
- *     OPTIONAL ULONG ExceptionData[]; */
-} UNWIND_INFO, *PUNWIND_INFO;
-
-typedef struct
-{
-       RUNTIME_FUNCTION runtimeFunction;
-       UNWIND_INFO unwindInfo;
-} MonoUnwindInfo, *PMonoUnwindInfo;
+#ifdef MONO_ARCH_HAVE_UNWIND_TABLE
 
 static void
 mono_arch_unwindinfo_create (gpointer* monoui)
 {
-       PMonoUnwindInfo newunwindinfo;
-       *monoui = newunwindinfo = g_new0 (MonoUnwindInfo, 1);
-       newunwindinfo->unwindInfo.Version = 1;
+       PUNWIND_INFO newunwindinfo;
+       *monoui = newunwindinfo = g_new0 (UNWIND_INFO, 1);
+       newunwindinfo->Version = 1;
 }
 
 void
-mono_arch_unwindinfo_add_push_nonvol (gpointer* monoui, gpointer codebegin, gpointer nextip, guchar reg )
+mono_arch_unwindinfo_add_push_nonvol (PUNWIND_INFO unwindinfo, MonoUnwindOp *unwind_op)
 {
-       PMonoUnwindInfo unwindinfo;
        PUNWIND_CODE unwindcode;
        guchar codeindex;
-       if (!*monoui)
-               mono_arch_unwindinfo_create (monoui);
-       
-       unwindinfo = (MonoUnwindInfo*)*monoui;
 
-       if (unwindinfo->unwindInfo.CountOfCodes >= MONO_MAX_UNWIND_CODES)
+       g_assert (unwindinfo != NULL);
+
+       if (unwindinfo->CountOfCodes >= MONO_MAX_UNWIND_CODES)
                g_error ("Larger allocation needed for the unwind information.");
 
-       codeindex = MONO_MAX_UNWIND_CODES - (++unwindinfo->unwindInfo.CountOfCodes);
-       unwindcode = &unwindinfo->unwindInfo.UnwindCode[codeindex];
-       unwindcode->UnwindOp = 0; /*UWOP_PUSH_NONVOL*/
-       unwindcode->CodeOffset = (((guchar*)nextip)-((guchar*)codebegin));
-       unwindcode->OpInfo = reg;
+       codeindex = MONO_MAX_UNWIND_CODES - (++unwindinfo->CountOfCodes);
+       unwindcode = &unwindinfo->UnwindCode [codeindex];
+       unwindcode->UnwindOp = UWOP_PUSH_NONVOL;
+       unwindcode->CodeOffset = (guchar)unwind_op->when;
+       unwindcode->OpInfo = unwind_op->reg;
 
-       if (unwindinfo->unwindInfo.SizeOfProlog >= unwindcode->CodeOffset)
+       if (unwindinfo->SizeOfProlog >= unwindcode->CodeOffset)
                g_error ("Adding unwind info in wrong order.");
-       
-       unwindinfo->unwindInfo.SizeOfProlog = unwindcode->CodeOffset;
+
+       unwindinfo->SizeOfProlog = unwindcode->CodeOffset;
 }
 
 void
-mono_arch_unwindinfo_add_set_fpreg (gpointer* monoui, gpointer codebegin, gpointer nextip, guchar reg )
+mono_arch_unwindinfo_add_set_fpreg (PUNWIND_INFO unwindinfo, MonoUnwindOp *unwind_op)
 {
-       PMonoUnwindInfo unwindinfo;
        PUNWIND_CODE unwindcode;
        guchar codeindex;
-       if (!*monoui)
-               mono_arch_unwindinfo_create (monoui);
-       
-       unwindinfo = (MonoUnwindInfo*)*monoui;
 
-       if (unwindinfo->unwindInfo.CountOfCodes + 1 >= MONO_MAX_UNWIND_CODES)
+       g_assert (unwindinfo != NULL);
+
+       if (unwindinfo->CountOfCodes + 1 >= MONO_MAX_UNWIND_CODES)
                g_error ("Larger allocation needed for the unwind information.");
 
-       codeindex = MONO_MAX_UNWIND_CODES - (unwindinfo->unwindInfo.CountOfCodes += 2);
-       unwindcode = &unwindinfo->unwindInfo.UnwindCode[codeindex];
-       unwindcode->FrameOffset = 0; /*Assuming no frame pointer offset for mono*/
-       unwindcode++;
-       unwindcode->UnwindOp = 3; /*UWOP_SET_FPREG*/
-       unwindcode->CodeOffset = (((guchar*)nextip)-((guchar*)codebegin));
-       unwindcode->OpInfo = reg;
-       
-       unwindinfo->unwindInfo.FrameRegister = reg;
+       codeindex = MONO_MAX_UNWIND_CODES - (++unwindinfo->CountOfCodes);
+       unwindcode = &unwindinfo->UnwindCode [codeindex];
+       unwindcode->UnwindOp = UWOP_SET_FPREG;
+       unwindcode->CodeOffset = (guchar)unwind_op->when;
 
-       if (unwindinfo->unwindInfo.SizeOfProlog >= unwindcode->CodeOffset)
+       g_assert (unwind_op->val % 16 == 0);
+       unwindinfo->FrameRegister = unwind_op->reg;
+       unwindinfo->FrameOffset = unwind_op->val / 16;
+
+       if (unwindinfo->SizeOfProlog >= unwindcode->CodeOffset)
                g_error ("Adding unwind info in wrong order.");
-       
-       unwindinfo->unwindInfo.SizeOfProlog = unwindcode->CodeOffset;
+
+       unwindinfo->SizeOfProlog = unwindcode->CodeOffset;
 }
 
 void
-mono_arch_unwindinfo_add_alloc_stack (gpointer* monoui, gpointer codebegin, gpointer nextip, guint size )
+mono_arch_unwindinfo_add_alloc_stack (PUNWIND_INFO unwindinfo, MonoUnwindOp *unwind_op)
 {
-       PMonoUnwindInfo unwindinfo;
        PUNWIND_CODE unwindcode;
        guchar codeindex;
        guchar codesneeded;
-       if (!*monoui)
-               mono_arch_unwindinfo_create (monoui);
-       
-       unwindinfo = (MonoUnwindInfo*)*monoui;
+       guint size;
+
+       g_assert (unwindinfo != NULL);
+
+       size = unwind_op->val;
 
        if (size < 0x8)
                g_error ("Stack allocation must be equal to or greater than 0x8.");
-       
+
        if (size <= 0x80)
                codesneeded = 1;
        else if (size <= 0x7FFF8)
                codesneeded = 2;
        else
                codesneeded = 3;
-       
-       if (unwindinfo->unwindInfo.CountOfCodes + codesneeded > MONO_MAX_UNWIND_CODES)
+
+       if (unwindinfo->CountOfCodes + codesneeded > MONO_MAX_UNWIND_CODES)
                g_error ("Larger allocation needed for the unwind information.");
 
-       codeindex = MONO_MAX_UNWIND_CODES - (unwindinfo->unwindInfo.CountOfCodes += codesneeded);
-       unwindcode = &unwindinfo->unwindInfo.UnwindCode[codeindex];
+       codeindex = MONO_MAX_UNWIND_CODES - (unwindinfo->CountOfCodes += codesneeded);
+       unwindcode = &unwindinfo->UnwindCode [codeindex];
+
+       unwindcode->CodeOffset = (guchar)unwind_op->when;
 
        if (codesneeded == 1) {
-               /*The size of the allocation is 
+               /*The size of the allocation is
                  (the number in the OpInfo member) times 8 plus 8*/
+               unwindcode->UnwindOp = UWOP_ALLOC_SMALL;
                unwindcode->OpInfo = (size - 8)/8;
-               unwindcode->UnwindOp = 2; /*UWOP_ALLOC_SMALL*/
        }
        else {
                if (codesneeded == 3) {
                        /*the unscaled size of the allocation is recorded
-                         in the next two slots in little-endian format*/
-                       *((unsigned int*)(&unwindcode->FrameOffset)) = size;
-                       unwindcode += 2;
+                         in the next two slots in little-endian format.
+                         NOTE, unwind codes are allocated from end to begining of list so
+                         unwind code will have right execution order. List is sorted on CodeOffset
+                         using descending sort order.*/
+                       unwindcode->UnwindOp = UWOP_ALLOC_LARGE;
                        unwindcode->OpInfo = 1;
+                       *((unsigned int*)(&(unwindcode + 1)->FrameOffset)) = size;
                }
                else {
                        /*the size of the allocation divided by 8
-                         is recorded in the next slot*/
-                       unwindcode->FrameOffset = size/8; 
-                       unwindcode++;   
+                         is recorded in the next slot.
+                         NOTE, unwind codes are allocated from end to begining of list so
+                         unwind code will have right execution order. List is sorted on CodeOffset
+                         using descending sort order.*/
+                       unwindcode->UnwindOp = UWOP_ALLOC_LARGE;
                        unwindcode->OpInfo = 0;
-                       
+                       (unwindcode + 1)->FrameOffset = (gushort)(size/8);
                }
-               unwindcode->UnwindOp = 1; /*UWOP_ALLOC_LARGE*/
        }
 
-       unwindcode->CodeOffset = (((guchar*)nextip)-((guchar*)codebegin));
-
-       if (unwindinfo->unwindInfo.SizeOfProlog >= unwindcode->CodeOffset)
+       if (unwindinfo->SizeOfProlog >= unwindcode->CodeOffset)
                g_error ("Adding unwind info in wrong order.");
-       
-       unwindinfo->unwindInfo.SizeOfProlog = unwindcode->CodeOffset;
+
+       unwindinfo->SizeOfProlog = unwindcode->CodeOffset;
 }
 
-guint
-mono_arch_unwindinfo_get_size (gpointer monoui)
+static gboolean g_dyn_func_table_inited;
+
+// Dynamic function table used when registering unwind info for OS unwind support.
+static GList *g_dynamic_function_table_begin;
+static GList *g_dynamic_function_table_end;
+
+// SRW lock (lightweight read/writer lock) protecting dynamic function table.
+static SRWLOCK g_dynamic_function_table_lock = SRWLOCK_INIT;
+
+// Module handle used when explicit loading ntdll.
+static HMODULE g_ntdll;
+
+// If Win8 or Win2012Server or later, use growable function tables instead
+// of callbacks. Callback solution will still be fallback on older systems.
+static RtlAddGrowableFunctionTablePtr g_rtl_add_growable_function_table;
+static RtlGrowFunctionTablePtr g_rtl_grow_function_table;
+static RtlDeleteGrowableFunctionTablePtr g_rtl_delete_growable_function_table;
+
+// When using function table callback solution an out of proc module is needed by
+// debuggers in order to read unwind info from debug target.
+#ifdef _MSC_VER
+#define MONO_DAC_MODULE TEXT("mono-2.0-dac-sgen.dll")
+#else
+#define MONO_DAC_MODULE TEXT("mono-2.0-sgen.dll")
+#endif
+
+#define MONO_DAC_MODULE_MAX_PATH 1024
+
+static void
+init_table_no_lock (void)
 {
-       PMonoUnwindInfo unwindinfo;
-       if (!monoui)
-               return 0;
-       
-       unwindinfo = (MonoUnwindInfo*)monoui;
-       return (8 + sizeof (MonoUnwindInfo)) - 
-               (sizeof (UNWIND_CODE) * (MONO_MAX_UNWIND_CODES - unwindinfo->unwindInfo.CountOfCodes));
+       if (g_dyn_func_table_inited == FALSE) {
+               g_assert_checked (g_dynamic_function_table_begin == NULL);
+               g_assert_checked (g_dynamic_function_table_end == NULL);
+               g_assert_checked (g_rtl_add_growable_function_table == NULL);
+               g_assert_checked (g_rtl_grow_function_table == NULL);
+               g_assert_checked (g_rtl_delete_growable_function_table == NULL);
+               g_assert_checked (g_ntdll == NULL);
+
+               // Load functions available on Win8/Win2012Server or later. If running on earlier
+               // systems the below GetProceAddress will fail, this is expected behavior.
+               if (GetModuleHandleEx (0, TEXT("ntdll.dll"), &g_ntdll) == TRUE) {
+                       g_rtl_add_growable_function_table = (RtlAddGrowableFunctionTablePtr)GetProcAddress (g_ntdll, "RtlAddGrowableFunctionTable");
+                       g_rtl_grow_function_table = (RtlGrowFunctionTablePtr)GetProcAddress (g_ntdll, "RtlGrowFunctionTable");
+                       g_rtl_delete_growable_function_table = (RtlDeleteGrowableFunctionTablePtr)GetProcAddress (g_ntdll, "RtlDeleteGrowableFunctionTable");
+               }
+
+               g_dyn_func_table_inited = TRUE;
+       }
+}
+
+void
+mono_arch_unwindinfo_init_table (void)
+{
+       if (g_dyn_func_table_inited == FALSE) {
+
+               AcquireSRWLockExclusive (&g_dynamic_function_table_lock);
+
+               init_table_no_lock ();
+
+               ReleaseSRWLockExclusive (&g_dynamic_function_table_lock);
+       }
+}
+
+static void
+terminate_table_no_lock (void)
+{
+       if (g_dyn_func_table_inited == TRUE) {
+               if (g_dynamic_function_table_begin != NULL) {
+                       // Free all list elements.
+                       for (GList *l = g_dynamic_function_table_begin; l; l = l->next) {
+                               if (l->data) {
+                                       g_free (l->data);
+                                       l->data = NULL;
+                               }
+                       }
+
+                       //Free the list.
+                       g_list_free (g_dynamic_function_table_begin);
+                       g_dynamic_function_table_begin = NULL;
+                       g_dynamic_function_table_end = NULL;
+               }
+
+               g_rtl_delete_growable_function_table = NULL;
+               g_rtl_grow_function_table = NULL;
+               g_rtl_add_growable_function_table = NULL;
+
+               if (g_ntdll != NULL) {
+                       FreeLibrary (g_ntdll);
+                       g_ntdll = NULL;
+               }
+
+               g_dyn_func_table_inited = FALSE;
+       }
+}
+
+void
+mono_arch_unwindinfo_terminate_table (void)
+{
+       if (g_dyn_func_table_inited == TRUE) {
+
+               AcquireSRWLockExclusive (&g_dynamic_function_table_lock);
+
+               terminate_table_no_lock ();
+
+               ReleaseSRWLockExclusive (&g_dynamic_function_table_lock);
+       }
+}
+
+static GList *
+fast_find_range_in_table_no_lock_ex (gsize begin_range, gsize end_range, gboolean *continue_search)
+{
+       GList *found_entry = NULL;
+
+       // Fast path, look at boundaries.
+       if (g_dynamic_function_table_begin != NULL) {
+               DynamicFunctionTableEntry *first_entry = g_dynamic_function_table_begin->data;
+               DynamicFunctionTableEntry *last_entry = (g_dynamic_function_table_end != NULL ) ? g_dynamic_function_table_end->data : first_entry;
+
+               // Sorted in descending order based on begin_range, check first item, that is the entry with highest range.
+               if (first_entry != NULL && first_entry->begin_range <= begin_range && first_entry->end_range >= end_range) {
+                               // Entry belongs to first entry in list.
+                               found_entry = g_dynamic_function_table_begin;
+                               *continue_search = FALSE;
+               } else {
+                       if (first_entry != NULL && first_entry->begin_range >= begin_range) {
+                               if (last_entry != NULL && last_entry->begin_range <= begin_range) {
+                                       // Entry has a range that could exist in table, continue search.
+                                       *continue_search = TRUE;
+                               }
+                       }
+               }
+       }
+
+       return found_entry;
+}
+
+static inline DynamicFunctionTableEntry *
+fast_find_range_in_table_no_lock (gsize begin_range, gsize end_range, gboolean *continue_search)
+{
+       GList *found_entry = fast_find_range_in_table_no_lock_ex (begin_range, end_range, continue_search);
+       return (found_entry != NULL) ? (DynamicFunctionTableEntry *)found_entry->data : NULL;
+}
+
+static GList *
+find_range_in_table_no_lock_ex (const gpointer code_block, gsize block_size)
+{
+       GList *found_entry = NULL;
+       gboolean continue_search = FALSE;
+
+       gsize begin_range = (gsize)code_block;
+       gsize end_range = begin_range + block_size;
+
+       // Fast path, check table boundaries.
+       found_entry = fast_find_range_in_table_no_lock_ex (begin_range, end_range, &continue_search);
+       if (found_entry || continue_search == FALSE)
+               return found_entry;
+
+       // Scan table for an entry including range.
+       for (GList *node = g_dynamic_function_table_begin; node; node = node->next) {
+               DynamicFunctionTableEntry *current_entry = (DynamicFunctionTableEntry *)node->data;
+               g_assert_checked (current_entry != NULL);
+
+               // Do we have a match?
+               if (current_entry->begin_range == begin_range && current_entry->end_range == end_range) {
+                       found_entry = node;
+                       break;
+               }
+       }
+
+       return found_entry;
+}
+
+static inline DynamicFunctionTableEntry *
+find_range_in_table_no_lock (const gpointer code_block, gsize block_size)
+{
+       GList *found_entry = find_range_in_table_no_lock_ex (code_block, block_size);
+       return (found_entry != NULL) ? (DynamicFunctionTableEntry *)found_entry->data : NULL;
+}
+
+static GList *
+find_pc_in_table_no_lock_ex (const gpointer pc)
+{
+       GList *found_entry = NULL;
+       gboolean continue_search = FALSE;
+
+       gsize begin_range = (gsize)pc;
+       gsize end_range = begin_range;
+
+       // Fast path, check table boundaries.
+       found_entry = fast_find_range_in_table_no_lock_ex (begin_range, begin_range, &continue_search);
+       if (found_entry || continue_search == FALSE)
+               return found_entry;
+
+       // Scan table for a entry including range.
+       for (GList *node = g_dynamic_function_table_begin; node; node = node->next) {
+               DynamicFunctionTableEntry *current_entry = (DynamicFunctionTableEntry *)node->data;
+               g_assert_checked (current_entry != NULL);
+
+               // Do we have a match?
+               if (current_entry->begin_range <= begin_range && current_entry->end_range >= end_range) {
+                       found_entry = node;
+                       break;
+               }
+       }
+
+       return found_entry;
+}
+
+static inline DynamicFunctionTableEntry *
+find_pc_in_table_no_lock (const gpointer pc)
+{
+       GList *found_entry = find_pc_in_table_no_lock_ex (pc);
+       return (found_entry != NULL) ? (DynamicFunctionTableEntry *)found_entry->data : NULL;
+}
+
+#ifdef ENABLE_CHECKED_BUILD_UNWINDINFO
+static void
+validate_table_no_lock (void)
+{
+       // Validation method checking that table is sorted as expected and don't include overlapped regions.
+       // Method will assert on failure to explicitly indicate what check failed.
+       if (g_dynamic_function_table_begin != NULL) {
+               g_assert_checked (g_dynamic_function_table_end != NULL);
+
+               DynamicFunctionTableEntry *prevoious_entry = NULL;
+               DynamicFunctionTableEntry *current_entry = NULL;
+               for (GList *node = g_dynamic_function_table_begin; node; node = node->next) {
+                       current_entry = (DynamicFunctionTableEntry *)node->data;
+
+                       g_assert_checked (current_entry != NULL);
+                       g_assert_checked (current_entry->end_range > current_entry->begin_range);
+
+                       if (prevoious_entry != NULL) {
+                               // List should be sorted in descending order on begin_range.
+                               g_assert_checked (prevoious_entry->begin_range > current_entry->begin_range);
+
+                               // Check for overlapped regions.
+                               g_assert_checked (prevoious_entry->begin_range >= current_entry->end_range);
+                       }
+
+                       prevoious_entry = current_entry;
+               }
+       }
+}
+
+#else
+
+static inline void
+validate_table_no_lock (void)
+{
+       ;
+}
+#endif /* ENABLE_CHECKED_BUILD_UNWINDINFO */
+
+// Forward declare.
+static PRUNTIME_FUNCTION MONO_GET_RUNTIME_FUNCTION_CALLBACK (DWORD64 ControlPc, IN PVOID Context);
+
+DynamicFunctionTableEntry *
+mono_arch_unwindinfo_insert_range_in_table (const gpointer code_block, gsize block_size)
+{
+       DynamicFunctionTableEntry *new_entry = NULL;
+
+       gsize begin_range = (gsize)code_block;
+       gsize end_range = begin_range + block_size;
+
+       AcquireSRWLockExclusive (&g_dynamic_function_table_lock);
+       init_table_no_lock ();
+       new_entry = find_range_in_table_no_lock (code_block, block_size);
+       if (new_entry == NULL) {
+               // Allocate new entry.
+               new_entry = g_new0 (DynamicFunctionTableEntry, 1);
+               if (new_entry != NULL) {
+
+                       // Pre-allocate RUNTIME_FUNCTION array, assume average method size of
+                       // MONO_UNWIND_INFO_RT_FUNC_SIZE bytes.
+                       InitializeSRWLock (&new_entry->lock);
+                       new_entry->handle = NULL;
+                       new_entry->begin_range = begin_range;
+                       new_entry->end_range = end_range;
+                       new_entry->rt_funcs_max_count = (block_size / MONO_UNWIND_INFO_RT_FUNC_SIZE) + 1;
+                       new_entry->rt_funcs_current_count = 0;
+                       new_entry->rt_funcs = g_new0 (RUNTIME_FUNCTION, new_entry->rt_funcs_max_count);
+
+                       if (new_entry->rt_funcs != NULL) {
+                               // Check insert on boundaries. List is sorted descending on begin_range.
+                               if (g_dynamic_function_table_begin == NULL) {
+                                       g_dynamic_function_table_begin = g_list_append (g_dynamic_function_table_begin, new_entry);
+                                       g_dynamic_function_table_end = g_dynamic_function_table_begin;
+                               } else if (((DynamicFunctionTableEntry *)(g_dynamic_function_table_begin->data))->begin_range < begin_range) {
+                                       // Insert at the head.
+                                       g_dynamic_function_table_begin = g_list_prepend (g_dynamic_function_table_begin, new_entry);
+                               } else if (((DynamicFunctionTableEntry *)(g_dynamic_function_table_end->data))->begin_range > begin_range) {
+                                       // Insert at tail.
+                                       g_list_append (g_dynamic_function_table_end, new_entry);
+                                       g_dynamic_function_table_end = g_dynamic_function_table_end->next;
+                               } else {
+                                       //Search and insert at correct position.
+                                       for (GList *node = g_dynamic_function_table_begin; node; node = node->next) {
+                                               DynamicFunctionTableEntry * current_entry = (DynamicFunctionTableEntry *)node->data;
+                                               g_assert_checked (current_entry != NULL);
+
+                                               if (current_entry->begin_range < new_entry->begin_range) {
+                                                       g_dynamic_function_table_begin = g_list_insert_before (g_dynamic_function_table_begin, node, new_entry);
+                                                       break;
+                                               }
+                                       }
+                               }
+
+                               // Register dynamic function table entry with OS.
+                               if (g_rtl_add_growable_function_table != NULL) {
+                                       // Allocate new growable handle table for entry.
+                                       g_assert_checked (new_entry->handle == NULL);
+                                       DWORD result = g_rtl_add_growable_function_table (&new_entry->handle,
+                                                                               new_entry->rt_funcs, new_entry->rt_funcs_current_count,
+                                                                               new_entry->rt_funcs_max_count, new_entry->begin_range, new_entry->end_range);
+                                       g_assert (!result);
+                               } else {
+                                       WCHAR buffer [MONO_DAC_MODULE_MAX_PATH] = { 0 };
+                                       WCHAR *path = buffer;
+
+                                       // DAC module should be in the same directory as the
+                                       // main executable.
+                                       GetModuleFileNameW (NULL, buffer, G_N_ELEMENTS(buffer));
+                                       path = wcsrchr (buffer, TEXT('\\'));
+                                       if (path != NULL) {
+                                               path++;
+                                               *path = TEXT('\0');
+                                       }
+
+                                       wcscat_s (buffer, G_N_ELEMENTS(buffer), MONO_DAC_MODULE);
+                                       path = buffer;
+
+                                       // Register function table callback + out of proc module.
+                                       new_entry->handle = (PVOID)((DWORD64)(new_entry->begin_range) | 3);
+                                       BOOLEAN result = RtlInstallFunctionTableCallback ((DWORD64)(new_entry->handle),
+                                                                               (DWORD64)(new_entry->begin_range), (DWORD)(new_entry->end_range - new_entry->begin_range),
+                                                                               MONO_GET_RUNTIME_FUNCTION_CALLBACK, new_entry, path);
+                                       g_assert(result);
+                               }
+
+                               // Only included in checked builds. Validates the structure of table after insert.
+                               validate_table_no_lock ();
+
+                       } else {
+                               g_free (new_entry);
+                               new_entry = NULL;
+                       }
+               }
+       }
+       ReleaseSRWLockExclusive (&g_dynamic_function_table_lock);
+
+       return new_entry;
+}
+
+static void
+remove_range_in_table_no_lock (GList *entry)
+{
+       if (entry != NULL) {
+               if (entry == g_dynamic_function_table_end)
+                       g_dynamic_function_table_end = entry->prev;
+
+               g_dynamic_function_table_begin = g_list_remove_link (g_dynamic_function_table_begin, entry);
+               DynamicFunctionTableEntry *removed_entry = (DynamicFunctionTableEntry *)entry->data;
+
+               g_assert_checked (removed_entry != NULL);
+               g_assert_checked (removed_entry->rt_funcs != NULL);
+
+               // Remove function table from OS.
+               if (removed_entry->handle != NULL) {
+                       if (g_rtl_delete_growable_function_table != NULL) {
+                               g_rtl_delete_growable_function_table (removed_entry->handle);
+                       } else {
+                               RtlDeleteFunctionTable ((PRUNTIME_FUNCTION)removed_entry->handle);
+                       }
+               }
+
+               g_free (removed_entry->rt_funcs);
+               g_free (removed_entry);
+
+               g_list_free_1 (entry);
+       }
+
+       // Only included in checked builds. Validates the structure of table after remove.
+       validate_table_no_lock ();
+}
+
+void
+mono_arch_unwindinfo_remove_pc_range_in_table (const gpointer code)
+{
+       AcquireSRWLockExclusive (&g_dynamic_function_table_lock);
+
+       GList *found_entry = find_pc_in_table_no_lock_ex (code);
+
+       g_assert_checked (found_entry != NULL || ((DynamicFunctionTableEntry *)found_entry->data)->begin_range == (gsize)code);
+       remove_range_in_table_no_lock (found_entry);
+
+       ReleaseSRWLockExclusive (&g_dynamic_function_table_lock);
+}
+
+void
+mono_arch_unwindinfo_remove_range_in_table (const gpointer code_block, gsize block_size)
+{
+       AcquireSRWLockExclusive (&g_dynamic_function_table_lock);
+
+       GList *found_entry = find_range_in_table_no_lock_ex (code_block, block_size);
+
+       g_assert_checked (found_entry != NULL || ((DynamicFunctionTableEntry *)found_entry->data)->begin_range == (gsize)code_block);
+       remove_range_in_table_no_lock (found_entry);
+
+       ReleaseSRWLockExclusive (&g_dynamic_function_table_lock);
+}
+
+PRUNTIME_FUNCTION
+mono_arch_unwindinfo_find_rt_func_in_table (const gpointer code, gsize code_size)
+{
+       PRUNTIME_FUNCTION found_rt_func = NULL;
+
+       gsize begin_range = (gsize)code;
+       gsize end_range = begin_range + code_size;
+
+       AcquireSRWLockShared (&g_dynamic_function_table_lock);
+
+       DynamicFunctionTableEntry *found_entry = find_pc_in_table_no_lock (code);
+
+       if (found_entry != NULL) {
+
+               AcquireSRWLockShared (&found_entry->lock);
+
+               g_assert_checked (found_entry->begin_range <= begin_range);
+               g_assert_checked (found_entry->end_range >= begin_range && found_entry->end_range >= end_range);
+               g_assert_checked (found_entry->rt_funcs != NULL);
+
+               for (int i = 0; i < found_entry->rt_funcs_current_count; ++i) {
+                       PRUNTIME_FUNCTION current_rt_func = (PRUNTIME_FUNCTION)(&found_entry->rt_funcs [i]);
+
+                       // Is this our RT function entry?
+                       if (found_entry->begin_range + current_rt_func->BeginAddress <= begin_range &&
+                               found_entry->begin_range + current_rt_func->EndAddress >= end_range) {
+                               found_rt_func = current_rt_func;
+                               break;
+                       }
+               }
+
+               ReleaseSRWLockShared (&found_entry->lock);
+       }
+
+       ReleaseSRWLockShared (&g_dynamic_function_table_lock);
+
+       return found_rt_func;
+}
+
+inline PRUNTIME_FUNCTION
+mono_arch_unwindinfo_find_pc_rt_func_in_table (const gpointer pc)
+{
+       return mono_arch_unwindinfo_find_rt_func_in_table (pc, 0);
+}
+
+#ifdef ENABLE_CHECKED_BUILD_UNWINDINFO
+static void
+validate_rt_funcs_in_table_no_lock (DynamicFunctionTableEntry *entry)
+{
+       // Validation method checking that runtime function table is sorted as expected and don't include overlapped regions.
+       // Method will assert on failure to explicitly indicate what check failed.
+       g_assert_checked (entry != NULL);
+       g_assert_checked (entry->rt_funcs_max_count >= entry->rt_funcs_current_count);
+       g_assert_checked (entry->rt_funcs != NULL);
+
+       PRUNTIME_FUNCTION current_rt_func = NULL;
+       PRUNTIME_FUNCTION previous_rt_func = NULL;
+       for (int i = 0; i < entry->rt_funcs_current_count; ++i) {
+               current_rt_func = &(entry->rt_funcs [i]);
+
+               g_assert_checked (current_rt_func->BeginAddress < current_rt_func->EndAddress);
+               g_assert_checked (current_rt_func->EndAddress <= current_rt_func->UnwindData);
+
+               if (previous_rt_func != NULL) {
+                       // List should be sorted in ascending order based on BeginAddress.
+                       g_assert_checked (previous_rt_func->BeginAddress < current_rt_func->BeginAddress);
+
+                       // Check for overlapped regions.
+                       g_assert_checked (previous_rt_func->EndAddress <= current_rt_func->BeginAddress);
+               }
+
+               previous_rt_func = current_rt_func;
+       }
+}
+
+#else
+
+static inline void
+validate_rt_funcs_in_table_no_lock (DynamicFunctionTableEntry *entry)
+{
+       ;
+}
+#endif /* ENABLE_CHECKED_BUILD_UNWINDINFO */
+
+PRUNTIME_FUNCTION
+mono_arch_unwindinfo_insert_rt_func_in_table (const gpointer code, gsize code_size)
+{
+       PRUNTIME_FUNCTION new_rt_func = NULL;
+
+       gsize begin_range = (gsize)code;
+       gsize end_range = begin_range + code_size;
+
+       AcquireSRWLockShared (&g_dynamic_function_table_lock);
+
+       DynamicFunctionTableEntry *found_entry = find_pc_in_table_no_lock (code);
+
+       if (found_entry != NULL) {
+
+               AcquireSRWLockExclusive (&found_entry->lock);
+
+               g_assert_checked (found_entry->begin_range <= begin_range);
+               g_assert_checked (found_entry->end_range >= begin_range && found_entry->end_range >= end_range);
+               g_assert_checked (found_entry->rt_funcs != NULL);
+               g_assert_checked ((guchar*)code - found_entry->begin_range >= 0);
+
+               gsize code_offset = (gsize)code - found_entry->begin_range;
+               gsize entry_count = found_entry->rt_funcs_current_count;
+               gsize max_entry_count = found_entry->rt_funcs_max_count;
+               PRUNTIME_FUNCTION current_rt_funcs = found_entry->rt_funcs;
+
+               RUNTIME_FUNCTION new_rt_func_data;
+               new_rt_func_data.BeginAddress = code_offset;
+               new_rt_func_data.EndAddress = code_offset + code_size;
+
+               gsize aligned_unwind_data = ALIGN_TO(end_range, sizeof (mgreg_t));
+               new_rt_func_data.UnwindData = aligned_unwind_data - found_entry->begin_range;
+
+               g_assert_checked (new_rt_func_data.UnwindData == ALIGN_TO(new_rt_func_data.EndAddress, sizeof (mgreg_t)));
+
+               PRUNTIME_FUNCTION new_rt_funcs = NULL;
+
+               // List needs to be sorted in ascending order based on BeginAddress (Windows requirement if list
+               // going to be directly reused in OS func tables. Check if we can append to end of existing table without realloc.
+               if (entry_count == 0 || (entry_count < max_entry_count) && (current_rt_funcs [entry_count - 1].BeginAddress) < code_offset) {
+                       new_rt_func = &(current_rt_funcs [entry_count]);
+                       *new_rt_func = new_rt_func_data;
+                       entry_count++;
+               } else {
+                       // No easy way out, need to realloc, grow to double size (or current max, if to small).
+                       max_entry_count = entry_count * 2 > max_entry_count ? entry_count * 2 : max_entry_count;
+                       new_rt_funcs = g_new0 (RUNTIME_FUNCTION, max_entry_count);
+
+                       if (new_rt_funcs != NULL) {
+                               gsize from_index = 0;
+                               gsize to_index = 0;
+
+                               // Copy from old table into new table. Make sure new rt func gets inserted
+                               // into correct location based on sort order.
+                               for (; from_index < entry_count; ++from_index) {
+                                       if (new_rt_func == NULL && current_rt_funcs [from_index].BeginAddress > new_rt_func_data.BeginAddress) {
+                                               new_rt_func = &(new_rt_funcs [to_index++]);
+                                               *new_rt_func = new_rt_func_data;
+                                       }
+
+                                       if (current_rt_funcs [from_index].UnwindData != 0)
+                                               new_rt_funcs [to_index++] = current_rt_funcs [from_index];
+                               }
+
+                               // If we didn't insert by now, put it last in the list.
+                               if (new_rt_func == NULL) {
+                                       new_rt_func = &(new_rt_funcs [to_index]);
+                                       *new_rt_func = new_rt_func_data;
+                               }
+                       }
+
+                       entry_count++;
+               }
+
+               // Update the stats for current entry.
+               found_entry->rt_funcs_current_count = entry_count;
+               found_entry->rt_funcs_max_count = max_entry_count;
+
+               if (new_rt_funcs == NULL && g_rtl_grow_function_table != NULL) {
+                       // No new table just report increase in use.
+                       g_assert_checked (found_entry->handle != NULL);
+                       g_rtl_grow_function_table (found_entry->handle, found_entry->rt_funcs_current_count);
+               } else if (new_rt_funcs != NULL && g_rtl_add_growable_function_table != NULL) {
+                       // New table, delete old table and rt funcs, and register a new one.
+                       g_assert_checked (g_rtl_delete_growable_function_table != NULL);
+                       g_rtl_delete_growable_function_table (found_entry->handle);
+                       found_entry->handle = NULL;
+                       g_free (found_entry->rt_funcs);
+                       found_entry->rt_funcs = new_rt_funcs;
+                       DWORD result = g_rtl_add_growable_function_table (&found_entry->handle,
+                                                               found_entry->rt_funcs, found_entry->rt_funcs_current_count,
+                                                               found_entry->rt_funcs_max_count, found_entry->begin_range, found_entry->end_range);
+                       g_assert (!result);
+               } else if (new_rt_funcs != NULL && g_rtl_add_growable_function_table == NULL) {
+                       // No table registered with OS, callback solution in use. Switch tables.
+                       g_free (found_entry->rt_funcs);
+                       found_entry->rt_funcs = new_rt_funcs;
+               } else if (new_rt_funcs == NULL && g_rtl_grow_function_table == NULL) {
+                       // No table registered with OS, callback solution in use, nothing to do.
+               } else {
+                       g_assert_not_reached ();
+               }
+
+               // Only included in checked builds. Validates the structure of table after insert.
+               validate_rt_funcs_in_table_no_lock (found_entry);
+
+               ReleaseSRWLockExclusive (&found_entry->lock);
+       }
+
+       ReleaseSRWLockShared (&g_dynamic_function_table_lock);
+
+       return new_rt_func;
 }
 
 static PRUNTIME_FUNCTION
 MONO_GET_RUNTIME_FUNCTION_CALLBACK ( DWORD64 ControlPc, IN PVOID Context )
 {
-       MonoJitInfo *ji;
-       guint64 pos;
-       PMonoUnwindInfo targetinfo;
-       MonoDomain *domain = mono_domain_get ();
+       return mono_arch_unwindinfo_find_pc_rt_func_in_table ((gpointer)ControlPc);
+}
+
+static void
+initialize_unwind_info_internal_ex (GSList *unwind_ops, PUNWIND_INFO unwindinfo)
+{
+       if (unwind_ops != NULL && unwindinfo != NULL) {
+               MonoUnwindOp *unwind_op_data;
+               gboolean sp_alloced = FALSE;
+               gboolean fp_alloced = FALSE;
+
+               // Replay collected unwind info and setup Windows format.
+               for (GSList *l = unwind_ops; l; l = l->next) {
+                       unwind_op_data = (MonoUnwindOp *)l->data;
+                       switch (unwind_op_data->op) {
+                               case DW_CFA_offset : {
+                                       // Pushes should go before SP/FP allocation to be compliant with Windows x64 ABI.
+                                       // TODO: DW_CFA_offset can also be used to move saved regs into frame.
+                                       if (unwind_op_data->reg != AMD64_RIP && sp_alloced == FALSE && fp_alloced == FALSE)
+                                               mono_arch_unwindinfo_add_push_nonvol (unwindinfo, unwind_op_data);
+                                       break;
+                               }
+                               case DW_CFA_mono_sp_alloc_info_win64 : {
+                                       mono_arch_unwindinfo_add_alloc_stack (unwindinfo, unwind_op_data);
+                                       sp_alloced = TRUE;
+                                       break;
+                               }
+                               case DW_CFA_mono_fp_alloc_info_win64 : {
+                                       mono_arch_unwindinfo_add_set_fpreg (unwindinfo, unwind_op_data);
+                                       fp_alloced = TRUE;
+                                       break;
+                               }
+                               default :
+                                       break;
+                       }
+               }
+       }
+}
 
-       ji = mini_jit_info_table_find (domain, (char*)ControlPc, NULL);
-       if (!ji)
-               return 0;
+static PUNWIND_INFO
+initialize_unwind_info_internal (GSList *unwind_ops)
+{
+       PUNWIND_INFO unwindinfo;
 
-       pos = (guint64)(((char*)ji->code_start) + ji->code_size);
-       
-       targetinfo = (PMonoUnwindInfo)ALIGN_TO (pos, 8);
+       mono_arch_unwindinfo_create (&unwindinfo);
+       initialize_unwind_info_internal_ex (unwind_ops, unwindinfo);
+
+       return unwindinfo;
+}
 
-       targetinfo->runtimeFunction.BeginAddress = ((DWORD64)ji->code_start) - ((DWORD64)Context);
-       targetinfo->runtimeFunction.EndAddress = pos - ((DWORD64)Context);
-       targetinfo->runtimeFunction.UnwindData = ((DWORD64)&targetinfo->unwindInfo) - ((DWORD64)Context);
+guchar
+mono_arch_unwindinfo_get_code_count (GSList *unwind_ops)
+{
+       UNWIND_INFO unwindinfo = {0};
+       initialize_unwind_info_internal_ex (unwind_ops, &unwindinfo);
+       return unwindinfo.CountOfCodes;
+}
 
-       return &targetinfo->runtimeFunction;
+guint
+mono_arch_unwindinfo_init_method_unwind_info (gpointer cfg)
+{
+       MonoCompile * current_cfg = (MonoCompile *)cfg;
+       g_assert (current_cfg->arch.unwindinfo == NULL);
+       current_cfg->arch.unwindinfo = initialize_unwind_info_internal (current_cfg->unwind_ops);
+       return mono_arch_unwindinfo_get_size (((PUNWIND_INFO)(current_cfg->arch.unwindinfo))->CountOfCodes);
 }
 
 void
-mono_arch_unwindinfo_install_unwind_info (gpointer* monoui, gpointer code, guint code_size)
+mono_arch_unwindinfo_install_method_unwind_info (gpointer *monoui, gpointer code, guint code_size)
 {
-       PMonoUnwindInfo unwindinfo, targetinfo;
+       PUNWIND_INFO unwindinfo, targetinfo;
        guchar codecount;
        guint64 targetlocation;
        if (!*monoui)
                return;
 
-       unwindinfo = (MonoUnwindInfo*)*monoui;
+       unwindinfo = (PUNWIND_INFO)*monoui;
        targetlocation = (guint64)&(((guchar*)code)[code_size]);
-       targetinfo = (PMonoUnwindInfo) ALIGN_TO(targetlocation, 8);
+       targetinfo = (PUNWIND_INFO) ALIGN_TO(targetlocation, sizeof (mgreg_t));
 
-       unwindinfo->runtimeFunction.EndAddress = code_size;
-       unwindinfo->runtimeFunction.UnwindData = ((guchar*)&targetinfo->unwindInfo) - ((guchar*)code);
-       
-       memcpy (targetinfo, unwindinfo, sizeof (MonoUnwindInfo) - (sizeof (UNWIND_CODE) * MONO_MAX_UNWIND_CODES));
-       
-       codecount = unwindinfo->unwindInfo.CountOfCodes;
+       memcpy (targetinfo, unwindinfo, sizeof (UNWIND_INFO) - (sizeof (UNWIND_CODE) * MONO_MAX_UNWIND_CODES));
+
+       codecount = unwindinfo->CountOfCodes;
+       if (codecount) {
+               memcpy (&targetinfo->UnwindCode [0], &unwindinfo->UnwindCode [MONO_MAX_UNWIND_CODES - codecount],
+                       sizeof (UNWIND_CODE) * codecount);
+       }
+
+#ifdef ENABLE_CHECKED_BUILD_UNWINDINFO
        if (codecount) {
-               memcpy (&targetinfo->unwindInfo.UnwindCode[0], &unwindinfo->unwindInfo.UnwindCode[MONO_MAX_UNWIND_CODES-codecount], 
-                       sizeof (UNWIND_CODE) * unwindinfo->unwindInfo.CountOfCodes);
+               // Validate the order of unwind op codes in checked builds. Offset should be in descending order.
+               // In first iteration previous == current, this is intended to handle UWOP_ALLOC_LARGE as first item.
+               int previous = 0;
+               for (int current = 0; current < codecount; current++) {
+                       g_assert_checked (targetinfo->UnwindCode [previous].CodeOffset >= targetinfo->UnwindCode [current].CodeOffset);
+                       previous = current;
+                       if (targetinfo->UnwindCode [current].UnwindOp == UWOP_ALLOC_LARGE) {
+                               if (targetinfo->UnwindCode [current].OpInfo == 0) {
+                                       current++;
+                               } else {
+                                       current += 2;
+                               }
+                       }
+               }
        }
+#endif /* ENABLE_CHECKED_BUILD_UNWINDINFO */
 
        g_free (unwindinfo);
        *monoui = 0;
+
+       // Register unwind info in table.
+       mono_arch_unwindinfo_insert_rt_func_in_table (code, code_size);
+}
+
+void
+mono_arch_unwindinfo_install_tramp_unwind_info (GSList *unwind_ops, gpointer code, guint code_size)
+{
+       PUNWIND_INFO unwindinfo = initialize_unwind_info_internal (unwind_ops);
+       if (unwindinfo != NULL) {
+               mono_arch_unwindinfo_install_method_unwind_info (&unwindinfo, code, code_size);
+       }
 }
 
 void
 mono_arch_code_chunk_new (void *chunk, int size)
 {
-       BOOLEAN success = RtlInstallFunctionTableCallback (((DWORD64)chunk) | 0x3, (DWORD64)chunk, size, MONO_GET_RUNTIME_FUNCTION_CALLBACK, chunk, NULL);
-       g_assert (success);
+       mono_arch_unwindinfo_insert_range_in_table (chunk, size);
 }
 
 void mono_arch_code_chunk_destroy (void *chunk)
 {
-       BOOLEAN success = RtlDeleteFunctionTable ((PRUNTIME_FUNCTION)((DWORD64)chunk | 0x03));
-       g_assert (success);
+       mono_arch_unwindinfo_remove_pc_range_in_table (chunk);
 }
-
-#endif /* defined(TARGET_WIN32) !defined(DISABLE_JIT) */
+#endif /* MONO_ARCH_HAVE_UNWIND_TABLE */
 
 #if MONO_SUPPORT_TASKLETS && !defined(DISABLE_JIT)
 MonoContinuationRestore
index 1269d5d5c7c122af0ba55d290199ef934422fa52..bdfc3bfcd3307010c0613900cdfd5553ff74d60b 100644 (file)
@@ -18,6 +18,7 @@
 #include "mini.h"
 #include <string.h>
 #include <math.h>
+#include <assert.h>
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
@@ -4540,10 +4541,16 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                /* Copy arguments on the stack to our argument area */
                                for (i = 0; i < call->stack_usage; i += sizeof(mgreg_t)) {
                                        amd64_mov_reg_membase (code, AMD64_RAX, AMD64_RSP, i, sizeof(mgreg_t));
-                                       amd64_mov_membase_reg (code, AMD64_RBP, 16 + i, AMD64_RAX, sizeof(mgreg_t));
+                                       amd64_mov_membase_reg (code, AMD64_RBP, ARGS_OFFSET + i, AMD64_RAX, sizeof(mgreg_t));
                                }
 
+#ifdef TARGET_WIN32
+                               amd64_lea_membase (code, AMD64_RSP, AMD64_RBP, 0);
+                               amd64_pop_reg (code, AMD64_RBP);
+                               mono_emit_unwind_op_same_value (cfg, code, AMD64_RBP);
+#else
                                amd64_leave (code);
+#endif
                        }
 
                        offset = code - cfg->native_code;
@@ -6476,6 +6483,16 @@ mono_arch_register_lowlevel_calls (void)
 {
        /* The signature doesn't matter */
        mono_register_jit_icall (mono_amd64_throw_exception, "mono_amd64_throw_exception", mono_create_icall_signature ("void"), TRUE);
+
+#if defined(TARGET_WIN32) || defined(HOST_WIN32)
+#if _MSC_VER
+       extern void __chkstk (void);
+       mono_register_jit_icall_full (__chkstk, "mono_chkstk_win64", NULL, TRUE, FALSE, "__chkstk");
+#else
+       extern void ___chkstk_ms (void);
+       mono_register_jit_icall_full (___chkstk_ms, "mono_chkstk_win64", NULL, TRUE, FALSE, "___chkstk_ms");
+#endif
+#endif
 }
 
 void
@@ -6543,6 +6560,41 @@ get_max_epilog_size (MonoCompile *cfg)
     } \
 } while (0)
 
+#ifdef TARGET_WIN32
+static guint8 *
+emit_prolog_setup_sp_win64 (MonoCompile *cfg, guint8 *code, int alloc_size, int *cfa_offset_input)
+{
+       int cfa_offset = *cfa_offset_input;
+
+       /* Allocate windows stack frame using stack probing method */
+       if (alloc_size) {
+
+               if (alloc_size >= 0x1000) {
+                       amd64_mov_reg_imm (code, AMD64_RAX, alloc_size);
+                       code = emit_call_body (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, "mono_chkstk_win64");
+               }
+
+               amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, alloc_size);
+               if (cfg->arch.omit_fp) {
+                       cfa_offset += alloc_size;
+                       mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
+                       async_exc_point (code);
+               }
+
+               // NOTE, in a standard win64 prolog the alloc unwind info is always emitted, but since mono
+               // uses a frame pointer with negative offsets and a standard win64 prolog assumes positive offsets, we can't
+               // emit sp alloc unwind metadata since the native OS unwinder will incorrectly restore sp. Excluding the alloc
+               // metadata on the other hand won't give the OS the information so it can just restore the frame pointer to sp and
+               // that will retrieve the expected results.
+               if (cfg->arch.omit_fp)
+                       mono_emit_unwind_op_sp_alloc (cfg, code, alloc_size);
+       }
+
+       *cfa_offset_input = cfa_offset;
+       return code;
+}
+#endif /* TARGET_WIN32 */
+
 guint8 *
 mono_arch_emit_prolog (MonoCompile *cfg)
 {
@@ -6573,8 +6625,9 @@ mono_arch_emit_prolog (MonoCompile *cfg)
        /* 
         * The prolog consists of the following parts:
         * FP present:
-        * - push rbp, mov rbp, rsp
-        * - save callee saved regs using pushes
+        * - push rbp
+        * - mov rbp, rsp
+        * - save callee saved regs using moves
         * - allocate frame
         * - save rgctx if needed
         * - save lmf if needed
@@ -6599,18 +6652,13 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
                mono_emit_unwind_op_offset (cfg, code, AMD64_RBP, - cfa_offset);
                async_exc_point (code);
-#ifdef TARGET_WIN32
-               mono_arch_unwindinfo_add_push_nonvol (&cfg->arch.unwindinfo, cfg->native_code, code, AMD64_RBP);
-#endif
                /* These are handled automatically by the stack marking code */
                mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF);
-               
+
                amd64_mov_reg_reg (code, AMD64_RBP, AMD64_RSP, sizeof(mgreg_t));
                mono_emit_unwind_op_def_cfa_reg (cfg, code, AMD64_RBP);
+               mono_emit_unwind_op_fp_alloc (cfg, code, AMD64_RBP, 0);
                async_exc_point (code);
-#ifdef TARGET_WIN32
-               mono_arch_unwindinfo_add_set_fpreg (&cfg->arch.unwindinfo, cfg->native_code, code, AMD64_RBP);
-#endif
        }
 
        /* The param area is always at offset 0 from sp */
@@ -6647,9 +6695,12 @@ mono_arch_emit_prolog (MonoCompile *cfg)
        cfg->arch.stack_alloc_size = alloc_size;
 
        /* Allocate stack frame */
+#ifdef TARGET_WIN32
+       code = emit_prolog_setup_sp_win64 (cfg, code, alloc_size, &cfa_offset);
+#else
        if (alloc_size) {
                /* See mono_emit_stack_alloc */
-#if defined(TARGET_WIN32) || defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
+#if defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
                guint32 remaining_size = alloc_size;
                /*FIXME handle unbounded code expansion, we should use a loop in case of more than X interactions*/
                guint32 required_code_size = ((remaining_size / 0x1000) + 1) * 11; /*11 is the max size of amd64_alu_reg_imm + amd64_test_membase_reg*/
@@ -6669,10 +6720,6 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                                mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
                        }
                        async_exc_point (code);
-#ifdef TARGET_WIN32
-                       if (cfg->arch.omit_fp) 
-                               mono_arch_unwindinfo_add_alloc_stack (&cfg->arch.unwindinfo, cfg->native_code, code, 0x1000);
-#endif
 
                        amd64_test_membase_reg (code, AMD64_RSP, 0, AMD64_RSP);
                        remaining_size -= 0x1000;
@@ -6684,10 +6731,6 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                                mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
                                async_exc_point (code);
                        }
-#ifdef TARGET_WIN32
-                       if (cfg->arch.omit_fp) 
-                               mono_arch_unwindinfo_add_alloc_stack (&cfg->arch.unwindinfo, cfg->native_code, code, remaining_size);
-#endif
                }
 #else
                amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, alloc_size);
@@ -6698,6 +6741,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                }
 #endif
        }
+#endif
 
        /* Stack alignment check */
 #if 0
@@ -7138,8 +7182,14 @@ mono_arch_emit_epilog (MonoCompile *cfg)
                        amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, cfg->arch.stack_alloc_size);
                }
        } else {
+#ifdef TARGET_WIN32
+               amd64_lea_membase (code, AMD64_RSP, AMD64_RBP, 0);
+               amd64_pop_reg (code, AMD64_RBP);
+               mono_emit_unwind_op_same_value (cfg, code, AMD64_RBP);
+#else
                amd64_leave (code);
                mono_emit_unwind_op_same_value (cfg, code, AMD64_RBP);
+#endif
        }
        mono_emit_unwind_op_def_cfa (cfg, code, AMD64_RSP, 8);
        async_exc_point (code);
@@ -7600,7 +7650,7 @@ get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, guint32 par
        unwind_ops = mono_arch_get_cie_program ();
 
        if (has_target) {
-               start = code = (guint8 *)mono_global_codeman_reserve (64);
+               start = code = (guint8 *)mono_global_codeman_reserve (64 + MONO_TRAMPOLINE_UNWINDINFO_SIZE(0));
 
                /* Replace the this argument with the target */
                amd64_mov_reg_reg (code, AMD64_RAX, AMD64_ARG_REG1, 8);
@@ -7608,8 +7658,9 @@ get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, guint32 par
                amd64_jump_membase (code, AMD64_RAX, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
 
                g_assert ((code - start) < 64);
+               g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_TRAMPOLINE_UNWINDINFO_SIZE(0)));
        } else {
-               start = code = (guint8 *)mono_global_codeman_reserve (64);
+               start = code = (guint8 *)mono_global_codeman_reserve (64 + MONO_TRAMPOLINE_UNWINDINFO_SIZE(0));
 
                if (param_count == 0) {
                        amd64_jump_membase (code, AMD64_ARG_REG1, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
@@ -7630,6 +7681,7 @@ get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, guint32 par
                        amd64_jump_membase (code, AMD64_RAX, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
                }
                g_assert ((code - start) < 64);
+               g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_TRAMPOLINE_UNWINDINFO_SIZE(0)));
        }
 
        mono_arch_flush_icache (start, code - start);
@@ -7670,7 +7722,7 @@ get_delegate_virtual_invoke_impl (MonoTrampInfo **info, gboolean load_imt_reg, i
        if (offset / (int)sizeof (gpointer) > MAX_VIRTUAL_DELEGATE_OFFSET)
                return NULL;
 
-       start = code = (guint8 *)mono_global_codeman_reserve (size);
+       start = code = (guint8 *)mono_global_codeman_reserve (size + MONO_TRAMPOLINE_UNWINDINFO_SIZE(0));
 
        unwind_ops = mono_arch_get_cie_program ();
 
@@ -7891,9 +7943,9 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTC
                size += item->chunk_size;
        }
        if (fail_tramp)
-               code = (guint8 *)mono_method_alloc_generic_virtual_trampoline (domain, size);
+               code = (guint8 *)mono_method_alloc_generic_virtual_trampoline (domain, size + MONO_TRAMPOLINE_UNWINDINFO_SIZE(0));
        else
-               code = (guint8 *)mono_domain_code_reserve (domain, size);
+               code = (guint8 *)mono_domain_code_reserve (domain, size + MONO_TRAMPOLINE_UNWINDINFO_SIZE(0));
        start = code;
 
        unwind_ops = mono_arch_get_cie_program ();
@@ -7984,6 +8036,7 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTC
        if (!fail_tramp)
                mono_stats.imt_trampolines_size += code - start;
        g_assert (code - start <= size);
+       g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_TRAMPOLINE_UNWINDINFO_SIZE(0)));
 
        mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL);
 
index 134b977c616eb7eb0d4fce628d0a55c49ad1997f..b857422ef643190d19d9fd8ac901a2956220d1f1 100644 (file)
@@ -47,6 +47,36 @@ void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler);
 
 LONG CALLBACK seh_handler(EXCEPTION_POINTERS* ep);
 
+typedef struct {
+       SRWLOCK lock;
+       PVOID handle;
+       gsize begin_range;
+       gsize end_range;
+       PRUNTIME_FUNCTION rt_funcs;
+       DWORD rt_funcs_current_count;
+       DWORD rt_funcs_max_count;
+} DynamicFunctionTableEntry;
+
+#define MONO_UNWIND_INFO_RT_FUNC_SIZE 128
+
+// On Win8/Win2012Server and later we can use dynamic growable function tables
+// instead of RtlInstallFunctionTableCallback. This gives us the benefit to
+// include all needed unwind upon registration.
+typedef DWORD (NTAPI* RtlAddGrowableFunctionTablePtr)(
+    _Out_ PVOID * DynamicTable,
+    _In_reads_(MaximumEntryCount) PRUNTIME_FUNCTION FunctionTable,
+    _In_ DWORD EntryCount,
+    _In_ DWORD MaximumEntryCount,
+    _In_ ULONG_PTR RangeBase,
+    _In_ ULONG_PTR RangeEnd);
+
+typedef VOID (NTAPI* RtlGrowFunctionTablePtr)(
+    _Inout_ PVOID DynamicTable,
+    _In_ DWORD NewEntryCount);
+
+typedef VOID (NTAPI* RtlDeleteGrowableFunctionTablePtr)(
+    _In_ PVOID DynamicTable);
+
 #endif /* HOST_WIN32 */
 
 #ifdef sun    // Solaris x86
@@ -178,7 +208,7 @@ typedef struct MonoCompileArch {
        gint32 async_point_count;
        gpointer vret_addr_loc;
 #ifdef HOST_WIN32
-       gpointer        unwindinfo;
+       gpointer unwindinfo;
 #endif
        gpointer seq_point_info_var;
        gpointer ss_trigger_page_var;
@@ -478,17 +508,110 @@ mono_amd64_handler_block_trampoline_helper (void);
 
 #if defined(TARGET_WIN32) && !defined(DISABLE_JIT)
 
-void mono_arch_unwindinfo_add_push_nonvol (gpointer* monoui, gpointer codebegin, gpointer nextip, guchar reg );
-void mono_arch_unwindinfo_add_set_fpreg (gpointer* monoui, gpointer codebegin, gpointer nextip, guchar reg );
-void mono_arch_unwindinfo_add_alloc_stack (gpointer* monoui, gpointer codebegin, gpointer nextip, guint size );
-guint mono_arch_unwindinfo_get_size (gpointer monoui);
-void mono_arch_unwindinfo_install_unwind_info (gpointer* monoui, gpointer code, guint code_size);
-
+#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
 #define MONO_ARCH_HAVE_UNWIND_TABLE 1
-
-void mono_arch_code_chunk_new (void *chunk, int size);
-void mono_arch_code_chunk_destroy (void *chunk);
 #define MONO_ARCH_HAVE_CODE_CHUNK_TRACKING 1
+
+#ifdef ENABLE_CHECKED_BUILD
+#define ENABLE_CHECKED_BUILD_UNWINDINFO
+#endif
+
+#define MONO_MAX_UNWIND_CODES 22
+
+typedef enum _UNWIND_OP_CODES {
+    UWOP_PUSH_NONVOL = 0, /* info == register number */
+    UWOP_ALLOC_LARGE,     /* no info, alloc size in next 2 slots */
+    UWOP_ALLOC_SMALL,     /* info == size of allocation / 8 - 1 */
+    UWOP_SET_FPREG,       /* no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 */
+    UWOP_SAVE_NONVOL,     /* info == register number, offset in next slot */
+    UWOP_SAVE_NONVOL_FAR, /* info == register number, offset in next 2 slots */
+    UWOP_SAVE_XMM128,     /* info == XMM reg number, offset in next slot */
+    UWOP_SAVE_XMM128_FAR, /* info == XMM reg number, offset in next 2 slots */
+    UWOP_PUSH_MACHFRAME   /* info == 0: no error-code, 1: error-code */
+} UNWIND_CODE_OPS;
+
+typedef union _UNWIND_CODE {
+    struct {
+        guchar CodeOffset;
+        guchar UnwindOp : 4;
+        guchar OpInfo   : 4;
+    };
+    gushort FrameOffset;
+} UNWIND_CODE, *PUNWIND_CODE;
+
+typedef struct _UNWIND_INFO {
+       guchar Version       : 3;
+       guchar Flags         : 5;
+       guchar SizeOfProlog;
+       guchar CountOfCodes;
+       guchar FrameRegister : 4;
+       guchar FrameOffset   : 4;
+       UNWIND_CODE UnwindCode[MONO_MAX_UNWIND_CODES];
+/*     UNWIND_CODE MoreUnwindCode[((CountOfCodes + 1) & ~1) - 1];
+ *     union {
+ *             OPTIONAL ULONG ExceptionHandler;
+ *             OPTIONAL ULONG FunctionEntry;
+ *     };
+ *     OPTIONAL ULONG ExceptionData[]; */
+} UNWIND_INFO, *PUNWIND_INFO;
+
+inline guint
+mono_arch_unwindinfo_get_size (guchar code_count)
+{
+       // Returned size will be used as the allocated size for unwind data trailing the memory used by compiled method.
+       // Windows x64 ABI have some requirements on the data written into this memory. Both the RUNTIME_FUNCTION
+       // and UNWIND_INFO struct needs to be DWORD aligned and the number of elements in unwind codes array
+       // should have an even number of entries, while the count stored in UNWIND_INFO struct should hold the real number
+       // of unwind codes. Adding extra bytes to the total size will make sure we can properly align the RUNTIME_FUNCTION
+       // struct. Since our UNWIND_INFO follows RUNTIME_FUNCTION struct in memory, it will automatically be DWORD aligned
+       // as well. Also make sure to allocate room for a padding UNWIND_CODE, if needed.
+       return (sizeof (mgreg_t) + sizeof (UNWIND_INFO)) -
+               (sizeof (UNWIND_CODE) * ((MONO_MAX_UNWIND_CODES - ((code_count + 1) & ~1))));
+}
+
+guchar
+mono_arch_unwindinfo_get_code_count (GSList *unwind_ops);
+
+guint
+mono_arch_unwindinfo_init_method_unwind_info (gpointer cfg);
+
+void
+mono_arch_unwindinfo_install_method_unwind_info (gpointer *monoui, gpointer code, guint code_size);
+
+void
+mono_arch_unwindinfo_install_tramp_unwind_info (GSList *unwind_ops, gpointer code, guint code_size);
+
+void
+mono_arch_code_chunk_new (void *chunk, int size);
+
+void
+mono_arch_code_chunk_destroy (void *chunk);
+
+#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
+#endif /* defined(TARGET_WIN32) && !defined(DISABLE_JIT) */
+
+#ifdef MONO_ARCH_HAVE_UNWIND_TABLE
+// Allocate additional size for max 3 unwind ops (push + fp or sp small|large) + unwind info struct trailing code buffer.
+#define MONO_TRAMPOLINE_UNWINDINFO_SIZE(max_code_count) (mono_arch_unwindinfo_get_size (max_code_count))
+#define MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE (MONO_TRAMPOLINE_UNWINDINFO_SIZE(3))
+
+inline gboolean
+mono_arch_unwindinfo_validate_size (GSList *unwind_ops, guint max_size)
+{
+       guint current_size = mono_arch_unwindinfo_get_size (mono_arch_unwindinfo_get_code_count (unwind_ops));
+       return current_size <= max_size;
+}
+
+#else
+
+#define MONO_TRAMPOLINE_UNWINDINFO_SIZE(max_code_count) 0
+#define MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE 0
+
+inline gboolean
+mono_arch_unwindinfo_validate_unwindinfo_size (GSList *unwind_ops, guint max_size)
+{
+       return TRUE;
+}
 #endif
 
 CallInfo* mono_arch_get_call_info (MonoMemPool *mp, MonoMethodSignature *sig);
index 9336b94f2d2bcc0f5935fa09163f6f5bfb9e0098..d573c31ce04be54923e55f37bb708299940016df 100644 (file)
@@ -505,6 +505,10 @@ mono_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
        mono_save_trampoline_xdebug_info (info);
        mono_lldb_save_trampoline_info (info);
 
+#ifdef MONO_ARCH_HAVE_UNWIND_TABLE
+       mono_arch_unwindinfo_install_tramp_unwind_info (info->unwind_ops, info->code, info->code_size);
+#endif
+
        /* Only register trampolines that have unwind infos */
        if (mono_get_root_domain () && copy->uw_info)
                register_trampoline_jit_info (domain, copy);
index 3d14e9cde783e8bf6f3ae6e51a068a0f789f9c03..41100fa3b35be60f47127f19ff3bff3792956bdf 100644 (file)
  */
 #define DW_CFA_mono_advance_loc DW_CFA_lo_user
 
+/*
+ * Mono extension, Windows x64 unwind ABI needs some more details around sp alloc size and fp offset.
+ */
+#if defined(TARGET_WIN32) && defined(TARGET_AMD64)
+#define DW_CFA_mono_sp_alloc_info_win64 (DW_CFA_lo_user + 1)
+#define DW_CFA_mono_fp_alloc_info_win64 (DW_CFA_lo_user + 2)
+#endif
+
 /* Represents one unwind instruction */
 typedef struct {
        guint8 op; /* One of DW_CFA_... */
@@ -107,6 +115,14 @@ typedef struct {
  */
 #define mono_emit_unwind_op_mark_loc(cfg,ip,n) mono_emit_unwind_op (cfg, (ip) - (cfg)->native_code, DW_CFA_mono_advance_loc, 0, (n))
 
+#if defined(TARGET_WIN32) && defined(TARGET_AMD64)
+#define mono_emit_unwind_op_sp_alloc(cfg,ip,size) mono_emit_unwind_op (cfg, (ip) - (cfg)->native_code, DW_CFA_mono_sp_alloc_info_win64, 0, (size))
+#define mono_emit_unwind_op_fp_alloc(cfg,ip,reg,size) mono_emit_unwind_op (cfg, (ip) - (cfg)->native_code, DW_CFA_mono_fp_alloc_info_win64, (reg), (size))
+#else
+#define mono_emit_unwind_op_sp_alloc(cfg,ip,size)
+#define mono_emit_unwind_op_fp_alloc(cfg,ip,reg,size)
+#endif
+
 /* Similar macros usable when a cfg is not available, like for trampolines */
 #define mono_add_unwind_op_def_cfa(op_list,code,buf,reg,offset) do { (op_list) = g_slist_append ((op_list), mono_create_unwind_op ((code) - (buf), DW_CFA_def_cfa, (reg), (offset))); } while (0)
 #define mono_add_unwind_op_def_cfa_reg(op_list,code,buf,reg) do { (op_list) = g_slist_append ((op_list), mono_create_unwind_op ((code) - (buf), DW_CFA_def_cfa_register, (reg), (0))); } while (0)
@@ -114,6 +130,14 @@ typedef struct {
 #define mono_add_unwind_op_same_value(op_list,code,buf,reg) do { (op_list) = g_slist_append ((op_list), mono_create_unwind_op ((code) - (buf), DW_CFA_same_value, (reg), 0)); } while (0)
 #define mono_add_unwind_op_offset(op_list,code,buf,reg,offset) do { (op_list) = g_slist_append ((op_list), mono_create_unwind_op ((code) - (buf), DW_CFA_offset, (reg), (offset))); } while (0)
 
+#if defined(TARGET_WIN32) && defined(TARGET_AMD64)
+#define mono_add_unwind_op_sp_alloc(op_list,code,buf,size) do { (op_list) = g_slist_append ((op_list), mono_create_unwind_op ((code) - (buf), DW_CFA_mono_sp_alloc_info_win64, 0, (size))); } while (0)
+#define mono_add_unwind_op_fp_alloc(op_list,code,buf,reg,size) do { (op_list) = g_slist_append ((op_list), mono_create_unwind_op ((code) - (buf), DW_CFA_mono_fp_alloc_info_win64, (reg), (size))); } while (0)
+#else
+#define mono_add_unwind_op_sp_alloc(op_list,code,buf,size)
+#define mono_add_unwind_op_fp_alloc(op_list,code,buf,reg,size)
+#endif
+
 #define mono_free_unwind_info(op_list) do { GSList *l; for (l = op_list; l; l = l->next) g_free (l->data); g_slist_free (op_list); op_list = NULL; } while (0)
 
 /* Pointer Encoding in the .eh_frame */
diff --git a/mono/mini/mini-windows-dlldac.c b/mono/mini/mini-windows-dlldac.c
new file mode 100644 (file)
index 0000000..5d19a16
--- /dev/null
@@ -0,0 +1,86 @@
+#include <config.h>
+
+#ifdef HOST_WIN32
+#include <winsock2.h>
+#include <windows.h>
+#include <winnt.h>
+
+#if defined(TARGET_AMD64) && !defined(DISABLE_JIT)
+#include "mono/mini/mini.h"
+#include "mono/mini/mini-amd64.h"
+#include "mono/utils/mono-publib.h"
+
+typedef enum _FUNCTION_TABLE_TYPE {
+    RF_SORTED,
+    RF_UNSORTED,
+    RF_CALLBACK
+} FUNCTION_TABLE_TYPE;
+
+typedef struct _DYNAMIC_FUNCTION_TABLE {
+    LIST_ENTRY Links;
+    PRUNTIME_FUNCTION FunctionTable;
+    LARGE_INTEGER TimeStamp;
+    ULONG64 MinimumAddress;
+    ULONG64 MaximumAddress;
+    ULONG64 BaseAddress;
+    PGET_RUNTIME_FUNCTION_CALLBACK Callback;
+    PVOID Context;
+    PWSTR OutOfProcessCallbackDll;
+    FUNCTION_TABLE_TYPE Type;
+    ULONG EntryCount;
+} DYNAMIC_FUNCTION_TABLE, *PDYNAMIC_FUNCTION_TABLE;
+
+typedef BOOL (ReadMemoryFunction)(PVOID user_context, LPCVOID base_address, PVOID buffer, SIZE_T size, SIZE_T *read);
+
+BOOL
+read_memory(PVOID user_context, LPCVOID base_address, PVOID buffer, SIZE_T size, SIZE_T* read)
+{
+    return ReadProcessMemory ((HANDLE)user_context, base_address, buffer, size, read);
+}
+
+MONO_API_EXPORT DWORD
+OutOfProcessFunctionTableCallbackEx (ReadMemoryFunction read_memory, PVOID user_context, PVOID table_address, PDWORD entries, PRUNTIME_FUNCTION *functions)
+{
+       DYNAMIC_FUNCTION_TABLE func_table = { 0 };
+       DynamicFunctionTableEntry func_table_entry = { 0 };
+       PRUNTIME_FUNCTION rt_funcs = NULL;
+       size_t reads = 0;
+       DWORD result = 0xC0000001;
+
+       if (read_memory (user_context, table_address, &func_table, sizeof (func_table), &reads)) {
+               if (func_table.Context != NULL && read_memory (user_context, func_table.Context, &func_table_entry, sizeof (func_table_entry), &reads)) {
+                       if (func_table_entry.rt_funcs_current_count != 0) {
+                               rt_funcs = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, func_table_entry.rt_funcs_current_count * sizeof (RUNTIME_FUNCTION));
+                               if (rt_funcs) {
+                                       if (read_memory (user_context, func_table_entry.rt_funcs, rt_funcs, func_table_entry.rt_funcs_current_count * sizeof (RUNTIME_FUNCTION), &reads)) {
+                                               *entries = func_table_entry.rt_funcs_current_count;
+                                               *functions = rt_funcs;
+                                               result = 0x00000000;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       return result;
+}
+
+MONO_API_EXPORT DWORD
+OutOfProcessFunctionTableCallback (HANDLE process, PVOID table_address, PDWORD entries, PRUNTIME_FUNCTION *functions)
+{
+       return OutOfProcessFunctionTableCallbackEx (&read_memory, process, table_address, entries, functions);
+}
+#endif /* defined(TARGET_AMD64) && !defined(DISABLE_JIT) */
+
+#ifdef _MSC_VER
+BOOL APIENTRY
+DllMain (HMODULE module_handle, DWORD reason, LPVOID reserved)
+{
+       return TRUE;
+}
+#endif
+
+#else
+
+MONO_EMPTY_SOURCE_FILE (mini_windows_dlldac);
+#endif /* HOST_WIN32 */
index 807cd5dd470cf7a2c230ede0b523020e1131d380..21dd9c8f7ea21323fda7a86424318f7037c027b6 100644 (file)
@@ -2273,7 +2273,7 @@ mono_codegen (MonoCompile *cfg)
        /* fixme: align to MONO_ARCH_CODE_ALIGNMENT */
 
 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
-       unwindlen = mono_arch_unwindinfo_get_size (cfg->arch.unwindinfo);
+       unwindlen = mono_arch_unwindinfo_init_method_unwind_info (cfg);
 #endif
 
        if (cfg->method->dynamic) {
@@ -2394,7 +2394,7 @@ mono_codegen (MonoCompile *cfg)
        mono_debug_close_method (cfg);
 
 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
-       mono_arch_unwindinfo_install_unwind_info (&cfg->arch.unwindinfo, cfg->native_code, cfg->code_len);
+       mono_arch_unwindinfo_install_method_unwind_info (&cfg->arch.unwindinfo, cfg->native_code, cfg->code_len);
 #endif
 }
 
index 96d1e71adad3a8a7d874731d0493da317bbdb6d3..5cf1f75540db1a921bea4ea3755ebc5edd7118dd 100644 (file)
@@ -161,7 +161,7 @@ mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
        int reg_area_size;
 
        buf_len = 2048;
-       buf = code = mono_global_codeman_reserve (buf_len);
+       buf = code = mono_global_codeman_reserve (buf_len + MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE);
 
        /*
         * We are being called by an gsharedvt arg trampoline, the info argument is in AMD64_RAX.
@@ -207,6 +207,7 @@ mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
 
        /* unwind markers 3/3 */
        mono_add_unwind_op_def_cfa_reg (unwind_ops, code, buf, AMD64_RBP);
+       mono_add_unwind_op_fp_alloc (unwind_ops, code, buf, AMD64_RBP, 0);
 
        /* setup the frame */
        amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, framesize);
@@ -443,10 +444,17 @@ mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
                mono_amd64_patch (br_ret [i], code);
 
        /* Exit code path */
+#if TARGET_WIN32
+       amd64_lea_membase (code, AMD64_RSP, AMD64_RBP, 0);
+       amd64_pop_reg (code, AMD64_RBP);
+       mono_add_unwind_op_same_value (unwind_ops, code, buf, AMD64_RBP);
+#else
        amd64_leave (code);
+#endif
        amd64_ret (code);
 
        g_assert ((code - buf) < buf_len);
+       g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE));
 
        if (info)
                *info = mono_tramp_info_create ("gsharedvt_trampoline", buf, code - buf, ji, unwind_ops);
index f0b3e9cbbedbae81c53f20dad9c5c1ccc626d69d..7ec7437eb30de65ba5895512bfc4619f583718d2 100644 (file)
@@ -4,6 +4,7 @@
  * Authors:
  *   Dietmar Maurer (dietmar@ximian.com)
  *   Zoltan Varga (vargaz@gmail.com)
+ *   Johan Lorensson (lateralusx.github@gmail.com)
  *
  * (C) 2001 Ximian, Inc.
  * Copyright 2003-2011 Novell, Inc (http://www.novell.com)
@@ -53,7 +54,7 @@ mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr)
 
        this_reg = mono_arch_get_this_arg_reg (NULL);
 
-       start = code = (guint8 *)mono_domain_code_reserve (domain, size);
+       start = code = (guint8 *)mono_domain_code_reserve (domain, size + MONO_TRAMPOLINE_UNWINDINFO_SIZE(0));
 
        unwind_ops = mono_arch_get_cie_program ();
 
@@ -62,6 +63,7 @@ mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr)
        amd64_mov_reg_imm (code, AMD64_RAX, addr);
        amd64_jump_reg (code, AMD64_RAX);
        g_assert ((code - start) < size);
+       g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_TRAMPOLINE_UNWINDINFO_SIZE(0)));
 
        mono_arch_flush_icache (start, code - start);
        mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE, m);
@@ -95,13 +97,14 @@ mono_arch_get_static_rgctx_trampoline (MonoMethod *m, MonoMethodRuntimeGenericCo
                buf_len = 30;
 #endif
 
-       start = code = (guint8 *)mono_domain_code_reserve (domain, buf_len);
+       start = code = (guint8 *)mono_domain_code_reserve (domain, buf_len + MONO_TRAMPOLINE_UNWINDINFO_SIZE(0));
 
        unwind_ops = mono_arch_get_cie_program ();
 
        amd64_mov_reg_imm (code, MONO_ARCH_RGCTX_REG, mrgctx);
        amd64_jump_code (code, addr);
        g_assert ((code - start) < buf_len);
+       g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_TRAMPOLINE_UNWINDINFO_SIZE(0)));
 
        mono_arch_flush_icache (start, code - start);
        mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL);
@@ -236,7 +239,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf
        else
                has_caller = TRUE;
 
-       code = buf = (guint8 *)mono_global_codeman_reserve (kMaxCodeSize);
+       code = buf = (guint8 *)mono_global_codeman_reserve (kMaxCodeSize + MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE);
 
        /* Compute stack frame size and offsets */
        offset = 0;
@@ -305,6 +308,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf
        orig_rsp_to_rbp_offset -= sizeof(mgreg_t);
        amd64_mov_reg_reg (code, AMD64_RBP, AMD64_RSP, sizeof(mgreg_t));
        mono_add_unwind_op_def_cfa_reg (unwind_ops, code, buf, AMD64_RBP);
+       mono_add_unwind_op_fp_alloc (unwind_ops, code, buf, AMD64_RBP, 0);
        amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, framesize);
 
        /* Compute the trampoline address from the return address */
@@ -504,7 +508,13 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf
         * We have an exception we want to throw in the caller's frame, so pop
         * the trampoline frame and throw from the caller.
         */
+#if TARGET_WIN32
+       amd64_lea_membase (code, AMD64_RSP, AMD64_RBP, 0);
+       amd64_pop_reg (code, AMD64_RBP);
+       mono_add_unwind_op_same_value (unwind_ops, code, buf, AMD64_RBP);
+#else
        amd64_leave (code);
+#endif
        /* We are in the parent frame, the exception is in rax */
        /*
         * EH is initialized after trampolines, so get the address of the variable
@@ -536,7 +546,13 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf
                amd64_movsd_reg_membase (code, i, AMD64_RBP, saved_fpregs_offset + (i * sizeof(mgreg_t)));
 
        /* Restore stack */
+#if TARGET_WIN32
+       amd64_lea_membase (code, AMD64_RSP, AMD64_RBP, 0);
+       amd64_pop_reg (code, AMD64_RBP);
+       mono_add_unwind_op_same_value (unwind_ops, code, buf, AMD64_RBP);
+#else
        amd64_leave (code);
+#endif
        cfa_offset -= sizeof (mgreg_t);
        mono_add_unwind_op_def_cfa (unwind_ops, code, buf, AMD64_RSP, cfa_offset);
 
@@ -550,6 +566,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf
        }
 
        g_assert ((code - buf) <= kMaxCodeSize);
+       g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE));
 
        mono_arch_flush_icache (buf, code - buf);
        mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL);
@@ -641,7 +658,7 @@ mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info
 
        tramp_size = 64 + 8 * depth;
 
-       code = buf = (guint8 *)mono_global_codeman_reserve (tramp_size);
+       code = buf = (guint8 *)mono_global_codeman_reserve (tramp_size + MONO_TRAMPOLINE_UNWINDINFO_SIZE(0));
 
        unwind_ops = mono_arch_get_cie_program ();
 
@@ -705,6 +722,7 @@ mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info
        mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL);
 
        g_assert (code - buf <= tramp_size);
+       g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_TRAMPOLINE_UNWINDINFO_SIZE(0)));
 
        char *name = mono_get_rgctx_fetch_trampoline_name (slot);
        *info = mono_tramp_info_create (name, buf, code - buf, ji, unwind_ops);
@@ -724,7 +742,7 @@ mono_arch_create_general_rgctx_lazy_fetch_trampoline (MonoTrampInfo **info, gboo
        g_assert (aot);
        tramp_size = 64;
 
-       code = buf = (guint8 *)mono_global_codeman_reserve (tramp_size);
+       code = buf = (guint8 *)mono_global_codeman_reserve (tramp_size + MONO_TRAMPOLINE_UNWINDINFO_SIZE(0));
 
        unwind_ops = mono_arch_get_cie_program ();
 
@@ -741,6 +759,7 @@ mono_arch_create_general_rgctx_lazy_fetch_trampoline (MonoTrampInfo **info, gboo
        mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL);
 
        g_assert (code - buf <= tramp_size);
+       g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_TRAMPOLINE_UNWINDINFO_SIZE(0)));
 
        if (info)
                *info = mono_tramp_info_create ("rgctx_fetch_trampoline_general", buf, code - buf, ji, unwind_ops);
@@ -778,7 +797,7 @@ mono_arch_create_handler_block_trampoline (MonoTrampInfo **info, gboolean aot)
        MonoJumpInfo *ji = NULL;
        GSList *unwind_ops;
 
-       code = buf = (guint8 *)mono_global_codeman_reserve (tramp_size);
+       code = buf = (guint8 *)mono_global_codeman_reserve (tramp_size + MONO_TRAMPOLINE_UNWINDINFO_SIZE(0));
 
        unwind_ops = mono_arch_get_cie_program ();
 
@@ -833,6 +852,7 @@ mono_arch_create_handler_block_trampoline (MonoTrampInfo **info, gboolean aot)
        mono_arch_flush_icache (buf, code - buf);
        mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL);
        g_assert (code - buf <= tramp_size);
+       g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_TRAMPOLINE_UNWINDINFO_SIZE(0)));
 
        *info = mono_tramp_info_create ("handler_block_trampoline", buf, code - buf, ji, unwind_ops);
 
@@ -886,7 +906,7 @@ mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gbo
        GSList *unwind_ops = NULL;
        MonoJumpInfo *ji = NULL;
 
-       code = buf = (guint8 *)mono_global_codeman_reserve (tramp_size);
+       code = buf = (guint8 *)mono_global_codeman_reserve (tramp_size + MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE);
 
        framesize = 0;
 #ifdef TARGET_WIN32
@@ -912,6 +932,7 @@ mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gbo
 
        amd64_mov_reg_reg (code, AMD64_RBP, AMD64_RSP, sizeof(mgreg_t));
        mono_add_unwind_op_def_cfa_reg (unwind_ops, code, buf, AMD64_RBP);
+       mono_add_unwind_op_fp_alloc (unwind_ops, code, buf, AMD64_RBP, 0);
        amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, framesize);
 
        gregs_offset = ctx_offset + MONO_STRUCT_OFFSET (MonoContext, gregs);
@@ -954,7 +975,13 @@ mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gbo
        amd64_mov_reg_membase (code, AMD64_R11, AMD64_RSP, gregs_offset + (AMD64_RIP * sizeof (mgreg_t)), sizeof (mgreg_t));
        amd64_mov_membase_reg (code, AMD64_RBP, sizeof (mgreg_t), AMD64_R11, sizeof (mgreg_t));
 
+#if TARGET_WIN32
+       amd64_lea_membase (code, AMD64_RSP, AMD64_RBP, 0);
+       amd64_pop_reg (code, AMD64_RBP);
+       mono_add_unwind_op_same_value (unwind_ops, code, buf, AMD64_RBP);
+#else
        amd64_leave (code);
+#endif
        cfa_offset -= sizeof (mgreg_t);
        mono_add_unwind_op_def_cfa (unwind_ops, code, buf, AMD64_RSP, cfa_offset);
        amd64_ret (code);
@@ -962,6 +989,7 @@ mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gbo
        mono_arch_flush_icache (code, code - buf);
        mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL);
        g_assert (code - buf <= tramp_size);
+       g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE));
 
        const char *tramp_name = single_step ? "sdb_single_step_trampoline" : "sdb_breakpoint_trampoline";
        *info = mono_tramp_info_create (tramp_name, buf, code - buf, ji, unwind_ops);
@@ -988,7 +1016,7 @@ mono_arch_get_enter_icall_trampoline (MonoTrampInfo **info)
        static int farg_regs[] = {AMD64_XMM0, AMD64_XMM1, AMD64_XMM2};
        int i, framesize = 0, off_rbp, off_methodargs, off_targetaddr;
 
-       start = code = (guint8 *) mono_global_codeman_reserve (256);
+       start = code = (guint8 *) mono_global_codeman_reserve (256 + MONO_TRAMPOLINE_UNWINDINFO_SIZE(0));
 
        off_rbp = -framesize;
 
index 3f8a2bdfcdedcd623a2c6014326496db48846901..f63171e52f171eaf656667e33b5a9297c37231f2 100644 (file)
@@ -449,6 +449,13 @@ mono_unwind_ops_encode_full (GSList *unwind_ops, guint32 *out_len, gboolean enab
                        g_assert (op->val == 0);
                        *p ++ = op->op;
                        break;
+#if defined(TARGET_WIN32) && defined(TARGET_AMD64)
+               case DW_CFA_mono_sp_alloc_info_win64:
+               case DW_CFA_mono_fp_alloc_info_win64:
+                       // Drop Windows specific unwind op's. These op's are currently
+                       // only used when registering unwind info with Windows OS unwinder.
+                       break;
+#endif
                default:
                        g_assert_not_reached ();
                        break;
diff --git a/msvc/libmonodac.vcxproj b/msvc/libmonodac.vcxproj
new file mode 100644 (file)
index 0000000..b8d2520
--- /dev/null
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup Label="ProjectConfigurations">\r
+    <ProjectConfiguration Include="Debug|x64">\r
+      <Configuration>Debug</Configuration>\r
+      <Platform>x64</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Release|x64">\r
+      <Configuration>Release</Configuration>\r
+      <Platform>x64</Platform>\r
+    </ProjectConfiguration>\r
+  </ItemGroup>\r
+  <PropertyGroup Label="Globals">\r
+    <ProjectGuid>{DC50997D-8A0D-4EB6-849B-9D7FBC39CE53}</ProjectGuid>\r
+    <RootNamespace>libmonodac</RootNamespace>\r
+    <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">\r
+    <ConfigurationType>DynamicLibrary</ConfigurationType>\r
+    <UseOfMfc>false</UseOfMfc>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+    <PlatformToolset>v140</PlatformToolset>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">\r
+    <ConfigurationType>DynamicLibrary</ConfigurationType>\r
+    <UseOfMfc>false</UseOfMfc>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+    <PlatformToolset>v140</PlatformToolset>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
+  <ImportGroup Label="ExtensionSettings">\r
+  </ImportGroup>\r
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+    <Import Project="mono.props" />\r
+  </ImportGroup>\r
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+    <Import Project="mono.props" />\r
+  </ImportGroup>\r
+  <PropertyGroup Label="UserMacros" />\r
+  <PropertyGroup>\r
+    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r
+    <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">mono-2.0-dac$(MONO_TARGET_SUFFIX)</TargetName>\r
+    <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">mono-2.0-dac$(MONO_TARGET_SUFFIX)</TargetName>\r
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(MONO_BUILD_DIR_PREFIX)$(Platform)\bin\$(Configuration)\</OutDir>\r
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(MONO_BUILD_DIR_PREFIX)$(Platform)\bin\$(Configuration)\</OutDir>\r
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(MONO_BUILD_DIR_PREFIX)$(Platform)\obj\$(ProjectName)$(MONO_TARGET_SUFFIX)\$(Configuration)\</IntDir>\r
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(MONO_BUILD_DIR_PREFIX)$(Platform)\obj\$(ProjectName)$(MONO_TARGET_SUFFIX)\$(Configuration)\</IntDir>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
+    <LinkIncremental>true</LinkIncremental>\r
+  </PropertyGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
+    <PreBuildEvent>\r
+      <Command>\r
+      </Command>\r
+    </PreBuildEvent>\r
+    <Midl>\r
+      <TargetEnvironment>X64</TargetEnvironment>\r
+    </Midl>\r
+    <ClCompile>\r
+      <AdditionalOptions>/D /NODEFAULTLIB:LIBCD" " %(AdditionalOptions)</AdditionalOptions>\r
+      <Optimization>Disabled</Optimization>\r
+      <InlineFunctionExpansion>Default</InlineFunctionExpansion>\r
+      <IntrinsicFunctions>true</IntrinsicFunctions>\r
+      <AdditionalIncludeDirectories>$(MONO_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <PreprocessorDefinitions>WIN32;WIN64;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <MinimalRebuild>true</MinimalRebuild>\r
+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <PrecompiledHeaderOutputFile>\r
+      </PrecompiledHeaderOutputFile>\r
+      <BrowseInformation>true</BrowseInformation>\r
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
+      <CompileAs>CompileAsC</CompileAs>\r
+      <DisableSpecificWarnings>4996;4018;4244;%(DisableSpecificWarnings)</DisableSpecificWarnings>\r
+    </ClCompile>\r
+    <ResourceCompile>\r
+      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <Culture>0x0409</Culture>\r
+    </ResourceCompile>\r
+    <ProjectReference>\r
+      <LinkLibraryDependencies>true</LinkLibraryDependencies>\r
+    </ProjectReference>\r
+    <Link>\r
+      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
+      <ModuleDefinitionFile>\r
+      </ModuleDefinitionFile>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <ImportLibrary>$(MONO_BUILD_DIR_PREFIX)$(Platform)\lib\$(Configuration)\$(TargetName).lib</ImportLibrary>\r
+      <TargetMachine>MachineX64</TargetMachine>\r
+    </Link>\r
+    <PostBuildEvent>\r
+      <Command>\r
+      </Command>\r
+    </PostBuildEvent>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
+    <PreBuildEvent>\r
+      <Command>\r
+      </Command>\r
+    </PreBuildEvent>\r
+    <Midl>\r
+      <TargetEnvironment>X64</TargetEnvironment>\r
+    </Midl>\r
+    <ClCompile>\r
+      <AdditionalOptions>/D /NODEFAULTLIB:LIBCD" " %(AdditionalOptions)</AdditionalOptions>\r
+      <Optimization>MinSpace</Optimization>\r
+      <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>\r
+      <IntrinsicFunctions>true</IntrinsicFunctions>\r
+      <AdditionalIncludeDirectories>$(MONO_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <PreprocessorDefinitions>WIN32;WIN64;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <StringPooling>true</StringPooling>\r
+      <FunctionLevelLinking>true</FunctionLevelLinking>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <PrecompiledHeaderOutputFile>\r
+      </PrecompiledHeaderOutputFile>\r
+      <CompileAs>CompileAsC</CompileAs>\r
+    </ClCompile>\r
+    <ResourceCompile>\r
+      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <Culture>0x0409</Culture>\r
+    </ResourceCompile>\r
+    <ProjectReference>\r
+      <LinkLibraryDependencies>true</LinkLibraryDependencies>\r
+    </ProjectReference>\r
+    <Link>\r
+      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
+      <ModuleDefinitionFile>\r
+      </ModuleDefinitionFile>\r
+      <ImportLibrary>$(MONO_BUILD_DIR_PREFIX)$(Platform)\lib\$(Configuration)\$(TargetName).lib</ImportLibrary>\r
+      <TargetMachine>MachineX64</TargetMachine>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+    </Link>\r
+    <PostBuildEvent>\r
+      <Command>\r
+      </Command>\r
+    </PostBuildEvent>\r
+  </ItemDefinitionGroup>\r
+  <ItemGroup>\r
+    <ProjectReference Include="libmono.vcxproj">\r
+      <Project>{cb0d9e92-293c-439c-9ac7-c5f59b6e0771}</Project>\r
+    </ProjectReference>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="..\mono\mini\mini-windows-dlldac.c" />\r
+  </ItemGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
+  <ImportGroup Label="ExtensionTargets">\r
+  </ImportGroup>\r
+</Project>
\ No newline at end of file
diff --git a/msvc/libmonodac.vcxproj.filters b/msvc/libmonodac.vcxproj.filters
new file mode 100644 (file)
index 0000000..998b4c7
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup>\r
+    <Filter Include="Header Files">\r
+      <UniqueIdentifier>{bdc9f80b-3045-49d2-bb7b-510450371395}</UniqueIdentifier>\r
+    </Filter>\r
+    <Filter Include="Resource Files">\r
+      <UniqueIdentifier>{f7700495-afaa-4d16-9aac-79d54d10de23}</UniqueIdentifier>\r
+    </Filter>\r
+    <Filter Include="Source Files">\r
+      <UniqueIdentifier>{5370c3c4-b6ec-4f8a-8b21-ce4e782720a6}</UniqueIdentifier>\r
+    </Filter>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="..\mono\mini\mini-windows-dlldac.c">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
+  </ItemGroup>\r
+</Project>
\ No newline at end of file
index 9a8a64ddfd483c8783ce94f727adf73c4d1312f4..193213c809b05a5c69ade222b03689eba06ad0a9 100644 (file)
@@ -210,6 +210,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mono-nunit-test", "mono-nun
                {92AE7622-5F58-4234-9A26-9EC71876B3F4} = {92AE7622-5F58-4234-9A26-9EC71876B3F4}\r
        EndProjectSection\r
 EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmonodac", "libmonodac.vcxproj", "{DC50997D-8A0D-4EB6-849B-9D7FBC39CE53}"\r
+EndProject\r
 Global\r
        GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
                Debug|Win32 = Debug|Win32\r
@@ -432,6 +434,12 @@ Global
                {0046B994-40A8-4C64-AC9D-429DC9177B54}.Release|Win32.Build.0 = Release|Win32\r
                {0046B994-40A8-4C64-AC9D-429DC9177B54}.Release|x64.ActiveCfg = Release|x64\r
                {0046B994-40A8-4C64-AC9D-429DC9177B54}.Release|x64.Build.0 = Release|x64\r
+               {DC50997D-8A0D-4EB6-849B-9D7FBC39CE53}.Debug|Win32.ActiveCfg = Debug|x64\r
+               {DC50997D-8A0D-4EB6-849B-9D7FBC39CE53}.Debug|x64.ActiveCfg = Debug|x64\r
+               {DC50997D-8A0D-4EB6-849B-9D7FBC39CE53}.Debug|x64.Build.0 = Debug|x64\r
+               {DC50997D-8A0D-4EB6-849B-9D7FBC39CE53}.Release|Win32.ActiveCfg = Release|x64\r
+               {DC50997D-8A0D-4EB6-849B-9D7FBC39CE53}.Release|x64.ActiveCfg = Release|x64\r
+               {DC50997D-8A0D-4EB6-849B-9D7FBC39CE53}.Release|x64.Build.0 = Release|x64\r
        EndGlobalSection\r
        GlobalSection(SolutionProperties) = preSolution\r
                HideSolutionNode = FALSE\r
@@ -468,11 +476,12 @@ Global
                {6C64262B-077B-4E12-AF91-9409ECCB75F6} = {BACF489E-EAEB-42BF-9E0A-C54D7CF455B4}\r
                {7BECCFA0-28A0-4995-9856-558560F720E6} = {A0068765-334B-414C-8E21-8376CD2EC9F6}\r
                {0046B994-40A8-4C64-AC9D-429DC9177B54} = {A0068765-334B-414C-8E21-8376CD2EC9F6}\r
+               {DC50997D-8A0D-4EB6-849B-9D7FBC39CE53} = {DE3617B4-17A8-4E5F-A00F-BA43D956881F}\r
        EndGlobalSection\r
        GlobalSection(ExtensibilityGlobals) = postSolution\r
-               AMDCaPersistentConfig = Debug|Win32\r
-               AMDCaPersistentStartup = mono\r
                AMDCaProjectFile = C:\Users\Owner\Development\monogit\mono\msvc\CodeAnalyst\mono.caw\r
+               AMDCaPersistentStartup = mono\r
+               AMDCaPersistentConfig = Debug|Win32\r
        EndGlobalSection\r
        GlobalSection(DPCodeReviewSolutionGUID) = preSolution\r
                DPCodeReviewSolutionGUID = {00000000-0000-0000-0000-000000000000}\r
index 73f67534019a237795922f6b7b855ce5e4c8a259..37a232b6a53a1715de5a96064b544663f18252ad 100644 (file)
 #error "Mono requires Windows Vista or later"
 #endif /* _WIN32_WINNT < 0x0600 */
 
+#ifndef HAVE_WINAPI_FAMILY_SUPPORT
+
+#define HAVE_WINAPI_FAMILY_SUPPORT
+
+/* WIN API Family support */
+#include <winapifamily.h>
+
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+       #define HAVE_CLASSIC_WINAPI_SUPPORT 1
+       #define HAVE_UWP_WINAPI_SUPPORT 0
+#elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
+       #define HAVE_CLASSIC_WINAPI_SUPPORT 0
+       #define HAVE_UWP_WINAPI_SUPPORT 1
+#ifndef HAVE_EXTERN_DEFINED_WINAPI_SUPPORT
+       #error Unsupported WINAPI family
+#endif
+#else
+       #define HAVE_CLASSIC_WINAPI_SUPPORT 0
+       #define HAVE_UWP_WINAPI_SUPPORT 0
+#ifndef HAVE_EXTERN_DEFINED_WINAPI_SUPPORT
+       #error Unsupported WINAPI family
+#endif
+#endif
+
+#endif
+
 /*
  * Features that are not required in the Windows port
  */
 #define HAVE_COMPLEX_H 1
 
 /* Define to 1 if you have the `system' function. */
+#if HAVE_WINAPI_FAMILY_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
 #define HAVE_SYSTEM 1
+#endif
+
 
 /* Have /dev/random */
 #define HAVE_CRYPT_RNG 1
 
 /* Version number of package */
 #define VERSION "#MONO_VERSION#"
-
-#ifndef HAVE_WINAPI_FAMILY_SUPPORT
-
-#define HAVE_WINAPI_FAMILY_SUPPORT
-
-/* WIN API Family support */
-#include <winapifamily.h>
-
-#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
-       #define HAVE_CLASSIC_WINAPI_SUPPORT 1
-       #define HAVE_UWP_WINAPI_SUPPORT 0
-#elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
-       #define HAVE_CLASSIC_WINAPI_SUPPORT 0
-       #define HAVE_UWP_WINAPI_SUPPORT 1
-#ifndef HAVE_EXTERN_DEFINED_WINAPI_SUPPORT
-       #error Unsupported WINAPI family
-#endif
-#else
-       #define HAVE_CLASSIC_WINAPI_SUPPORT 0
-       #define HAVE_UWP_WINAPI_SUPPORT 0
-#ifndef HAVE_EXTERN_DEFINED_WINAPI_SUPPORT
-       #error Unsupported WINAPI family
-#endif
-#endif
-
-#endif
 #endif