diff options
-rwxr-xr-x | eglib/winconfig.h | 52 | ||||
-rwxr-xr-x | mono/mini/Makefile.am.in | 3 | ||||
-rw-r--r-- | mono/mini/aot-compiler.c | 2 | ||||
-rw-r--r-- | mono/mini/exceptions-amd64.c | 944 | ||||
-rw-r--r-- | mono/mini/mini-amd64.c | 101 | ||||
-rw-r--r-- | mono/mini/mini-amd64.h | 143 | ||||
-rw-r--r-- | mono/mini/mini-runtime.c | 4 | ||||
-rw-r--r-- | mono/mini/mini-unwind.h | 24 | ||||
-rw-r--r-- | mono/mini/mini-windows-dlldac.c | 86 | ||||
-rw-r--r-- | mono/mini/mini.c | 4 | ||||
-rw-r--r-- | mono/mini/tramp-amd64-gsharedvt.c | 10 | ||||
-rw-r--r-- | mono/mini/tramp-amd64.c | 44 | ||||
-rw-r--r-- | mono/mini/unwind.c | 7 | ||||
-rw-r--r-- | msvc/libmonodac.vcxproj | 155 | ||||
-rw-r--r-- | msvc/libmonodac.vcxproj.filters | 19 | ||||
-rw-r--r-- | msvc/mono.sln | 13 | ||||
-rw-r--r-- | winconfig.h | 55 |
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 |