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

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xeglib/winconfig.h52
-rwxr-xr-xmono/mini/Makefile.am.in3
-rw-r--r--mono/mini/aot-compiler.c2
-rw-r--r--mono/mini/exceptions-amd64.c944
-rw-r--r--mono/mini/mini-amd64.c101
-rw-r--r--mono/mini/mini-amd64.h143
-rw-r--r--mono/mini/mini-runtime.c4
-rw-r--r--mono/mini/mini-unwind.h24
-rw-r--r--mono/mini/mini-windows-dlldac.c86
-rw-r--r--mono/mini/mini.c4
-rw-r--r--mono/mini/tramp-amd64-gsharedvt.c10
-rw-r--r--mono/mini/tramp-amd64.c44
-rw-r--r--mono/mini/unwind.c7
-rw-r--r--msvc/libmonodac.vcxproj155
-rw-r--r--msvc/libmonodac.vcxproj.filters19
-rw-r--r--msvc/mono.sln13
-rw-r--r--winconfig.h55
17 files changed, 1408 insertions, 258 deletions
diff --git a/eglib/winconfig.h b/eglib/winconfig.h
index 238250bba05..31bbf89a6a1 100755
--- a/eglib/winconfig.h
+++ b/eglib/winconfig.h
@@ -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
@@ -78,30 +104,4 @@
#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
diff --git a/mono/mini/Makefile.am.in b/mono/mini/Makefile.am.in
index e4a126a7e29..4592dec23c1 100755
--- a/mono/mini/Makefile.am.in
+++ b/mono/mini/Makefile.am.in
@@ -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
diff --git a/mono/mini/aot-compiler.c b/mono/mini/aot-compiler.c
index c3ef0287892..22dc64f9519 100644
--- a/mono/mini/aot-compiler.c
+++ b/mono/mini/aot-compiler.c
@@ -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);
diff --git a/mono/mini/exceptions-amd64.c b/mono/mini/exceptions-amd64.c
index 38c333c466c..383aea2f447 100644
--- a/mono/mini/exceptions-amd64.c
+++ b/mono/mini/exceptions-amd64.c
@@ -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
diff --git a/mono/mini/mini-amd64.c b/mono/mini/mini-amd64.c
index 1269d5d5c7c..bdfc3bfcd33 100644
--- a/mono/mini/mini-amd64.c
+++ b/mono/mini/mini-amd64.c
@@ -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);
diff --git a/mono/mini/mini-amd64.h b/mono/mini/mini-amd64.h
index 134b977c616..b857422ef64 100644
--- a/mono/mini/mini-amd64.h
+++ b/mono/mini/mini-amd64.h
@@ -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);
diff --git a/mono/mini/mini-runtime.c b/mono/mini/mini-runtime.c
index 9336b94f2d2..d573c31ce04 100644
--- a/mono/mini/mini-runtime.c
+++ b/mono/mini/mini-runtime.c
@@ -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);
diff --git a/mono/mini/mini-unwind.h b/mono/mini/mini-unwind.h
index 3d14e9cde78..41100fa3b35 100644
--- a/mono/mini/mini-unwind.h
+++ b/mono/mini/mini-unwind.h
@@ -72,6 +72,14 @@
*/
#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
index 00000000000..5d19a163546
--- /dev/null
+++ b/mono/mini/mini-windows-dlldac.c
@@ -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 */
diff --git a/mono/mini/mini.c b/mono/mini/mini.c
index 807cd5dd470..21dd9c8f7ea 100644
--- a/mono/mini/mini.c
+++ b/mono/mini/mini.c
@@ -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
}
diff --git a/mono/mini/tramp-amd64-gsharedvt.c b/mono/mini/tramp-amd64-gsharedvt.c
index 96d1e71adad..5cf1f75540d 100644
--- a/mono/mini/tramp-amd64-gsharedvt.c
+++ b/mono/mini/tramp-amd64-gsharedvt.c
@@ -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);
diff --git a/mono/mini/tramp-amd64.c b/mono/mini/tramp-amd64.c
index f0b3e9cbbed..7ec7437eb30 100644
--- a/mono/mini/tramp-amd64.c
+++ b/mono/mini/tramp-amd64.c
@@ -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;
diff --git a/mono/mini/unwind.c b/mono/mini/unwind.c
index 3f8a2bdfcde..f63171e52f1 100644
--- a/mono/mini/unwind.c
+++ b/mono/mini/unwind.c
@@ -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
index 00000000000..b8d2520fd58
--- /dev/null
+++ b/msvc/libmonodac.vcxproj
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{DC50997D-8A0D-4EB6-849B-9D7FBC39CE53}</ProjectGuid>
+ <RootNamespace>libmonodac</RootNamespace>
+ <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v140</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v140</PlatformToolset>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="mono.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="mono.props" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">mono-2.0-dac$(MONO_TARGET_SUFFIX)</TargetName>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">mono-2.0-dac$(MONO_TARGET_SUFFIX)</TargetName>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(MONO_BUILD_DIR_PREFIX)$(Platform)\bin\$(Configuration)\</OutDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(MONO_BUILD_DIR_PREFIX)$(Platform)\bin\$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(MONO_BUILD_DIR_PREFIX)$(Platform)\obj\$(ProjectName)$(MONO_TARGET_SUFFIX)\$(Configuration)\</IntDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(MONO_BUILD_DIR_PREFIX)$(Platform)\obj\$(ProjectName)$(MONO_TARGET_SUFFIX)\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <PreBuildEvent>
+ <Command>
+ </Command>
+ </PreBuildEvent>
+ <Midl>
+ <TargetEnvironment>X64</TargetEnvironment>
+ </Midl>
+ <ClCompile>
+ <AdditionalOptions>/D /NODEFAULTLIB:LIBCD" " %(AdditionalOptions)</AdditionalOptions>
+ <Optimization>Disabled</Optimization>
+ <InlineFunctionExpansion>Default</InlineFunctionExpansion>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <AdditionalIncludeDirectories>$(MONO_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;WIN64;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <PrecompiledHeaderOutputFile>
+ </PrecompiledHeaderOutputFile>
+ <BrowseInformation>true</BrowseInformation>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <CompileAs>CompileAsC</CompileAs>
+ <DisableSpecificWarnings>4996;4018;4244;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0409</Culture>
+ </ResourceCompile>
+ <ProjectReference>
+ <LinkLibraryDependencies>true</LinkLibraryDependencies>
+ </ProjectReference>
+ <Link>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <ModuleDefinitionFile>
+ </ModuleDefinitionFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ImportLibrary>$(MONO_BUILD_DIR_PREFIX)$(Platform)\lib\$(Configuration)\$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX64</TargetMachine>
+ </Link>
+ <PostBuildEvent>
+ <Command>
+ </Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <PreBuildEvent>
+ <Command>
+ </Command>
+ </PreBuildEvent>
+ <Midl>
+ <TargetEnvironment>X64</TargetEnvironment>
+ </Midl>
+ <ClCompile>
+ <AdditionalOptions>/D /NODEFAULTLIB:LIBCD" " %(AdditionalOptions)</AdditionalOptions>
+ <Optimization>MinSpace</Optimization>
+ <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <AdditionalIncludeDirectories>$(MONO_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;WIN64;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <PrecompiledHeaderOutputFile>
+ </PrecompiledHeaderOutputFile>
+ <CompileAs>CompileAsC</CompileAs>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0409</Culture>
+ </ResourceCompile>
+ <ProjectReference>
+ <LinkLibraryDependencies>true</LinkLibraryDependencies>
+ </ProjectReference>
+ <Link>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <ModuleDefinitionFile>
+ </ModuleDefinitionFile>
+ <ImportLibrary>$(MONO_BUILD_DIR_PREFIX)$(Platform)\lib\$(Configuration)\$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX64</TargetMachine>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ <PostBuildEvent>
+ <Command>
+ </Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ProjectReference Include="libmono.vcxproj">
+ <Project>{cb0d9e92-293c-439c-9ac7-c5f59b6e0771}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\mono\mini\mini-windows-dlldac.c" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/msvc/libmonodac.vcxproj.filters b/msvc/libmonodac.vcxproj.filters
new file mode 100644
index 00000000000..998b4c7c272
--- /dev/null
+++ b/msvc/libmonodac.vcxproj.filters
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{bdc9f80b-3045-49d2-bb7b-510450371395}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{f7700495-afaa-4d16-9aac-79d54d10de23}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{5370c3c4-b6ec-4f8a-8b21-ce4e782720a6}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\mono\mini\mini-windows-dlldac.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/msvc/mono.sln b/msvc/mono.sln
index 9a8a64ddfd4..193213c809b 100644
--- a/msvc/mono.sln
+++ b/msvc/mono.sln
@@ -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}
EndProjectSection
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmonodac", "libmonodac.vcxproj", "{DC50997D-8A0D-4EB6-849B-9D7FBC39CE53}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@@ -432,6 +434,12 @@ Global
{0046B994-40A8-4C64-AC9D-429DC9177B54}.Release|Win32.Build.0 = Release|Win32
{0046B994-40A8-4C64-AC9D-429DC9177B54}.Release|x64.ActiveCfg = Release|x64
{0046B994-40A8-4C64-AC9D-429DC9177B54}.Release|x64.Build.0 = Release|x64
+ {DC50997D-8A0D-4EB6-849B-9D7FBC39CE53}.Debug|Win32.ActiveCfg = Debug|x64
+ {DC50997D-8A0D-4EB6-849B-9D7FBC39CE53}.Debug|x64.ActiveCfg = Debug|x64
+ {DC50997D-8A0D-4EB6-849B-9D7FBC39CE53}.Debug|x64.Build.0 = Debug|x64
+ {DC50997D-8A0D-4EB6-849B-9D7FBC39CE53}.Release|Win32.ActiveCfg = Release|x64
+ {DC50997D-8A0D-4EB6-849B-9D7FBC39CE53}.Release|x64.ActiveCfg = Release|x64
+ {DC50997D-8A0D-4EB6-849B-9D7FBC39CE53}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -468,11 +476,12 @@ Global
{6C64262B-077B-4E12-AF91-9409ECCB75F6} = {BACF489E-EAEB-42BF-9E0A-C54D7CF455B4}
{7BECCFA0-28A0-4995-9856-558560F720E6} = {A0068765-334B-414C-8E21-8376CD2EC9F6}
{0046B994-40A8-4C64-AC9D-429DC9177B54} = {A0068765-334B-414C-8E21-8376CD2EC9F6}
+ {DC50997D-8A0D-4EB6-849B-9D7FBC39CE53} = {DE3617B4-17A8-4E5F-A00F-BA43D956881F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
- AMDCaPersistentConfig = Debug|Win32
- AMDCaPersistentStartup = mono
AMDCaProjectFile = C:\Users\Owner\Development\monogit\mono\msvc\CodeAnalyst\mono.caw
+ AMDCaPersistentStartup = mono
+ AMDCaPersistentConfig = Debug|Win32
EndGlobalSection
GlobalSection(DPCodeReviewSolutionGUID) = preSolution
DPCodeReviewSolutionGUID = {00000000-0000-0000-0000-000000000000}
diff --git a/winconfig.h b/winconfig.h
index 73f67534019..37a232b6a53 100644
--- a/winconfig.h
+++ b/winconfig.h
@@ -26,6 +26,32 @@
#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
*/
@@ -101,7 +127,10 @@
#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
@@ -643,30 +672,4 @@
/* 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