diff --git a/src/coreclr/vm/ClrEtwAll.man b/src/coreclr/vm/ClrEtwAll.man index 761d650be7e51d..12841164e9daf9 100644 --- a/src/coreclr/vm/ClrEtwAll.man +++ b/src/coreclr/vm/ClrEtwAll.man @@ -611,6 +611,7 @@ + @@ -4309,6 +4310,7 @@ + @@ -8678,6 +8680,7 @@ + @@ -8808,6 +8811,7 @@ + diff --git a/src/mono/mono/metadata/image-internals.h b/src/mono/mono/metadata/image-internals.h index a424c125987baf..2caaebb2b768d7 100644 --- a/src/mono/mono/metadata/image-internals.h +++ b/src/mono/mono/metadata/image-internals.h @@ -10,8 +10,8 @@ #include typedef struct { - int dont_care_about_cli : 1; - int dont_care_about_pecoff : 1; + gboolean dont_care_about_cli : 1; + gboolean dont_care_about_pecoff : 1; } MonoImageLoadOptions; typedef struct { diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index a4b1e021ad2ba8..5fb5076a9f1064 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -13314,25 +13314,25 @@ add_mibc_group_method_methods (MonoAotCompile *acfg, MonoMethod *mibcGroupMethod int count = 0; MibcGroupMethodEntryState state = FIND_METHOD_TYPE_ENTRY_START; - uint8_t *cur = (uint8_t*)mibcGroupMethodHeader->code; - uint8_t *end = (uint8_t*)mibcGroupMethodHeader->code + mibcGroupMethodHeader->code_size; + const unsigned char *cur = mibcGroupMethodHeader->code; + const unsigned char *end = mibcGroupMethodHeader->code + mibcGroupMethodHeader->code_size; while (cur < end) { MonoOpcodeEnum il_op; - const unsigned char *opcodeIp = (unsigned char*)cur; - const unsigned char *opcodeEnd = (unsigned char*)end; - cur += mono_opcode_value_and_size (&opcodeIp, opcodeEnd, &il_op); + const int op_size = mono_opcode_value_and_size (&cur, end, &il_op); if (state == FIND_METHOD_TYPE_ENTRY_END) { if (il_op == MONO_CEE_POP) state = FIND_METHOD_TYPE_ENTRY_START; + cur += op_size; continue; } g_assert (il_op == MONO_CEE_LDTOKEN); state = FIND_METHOD_TYPE_ENTRY_END; - g_assert (opcodeIp + 4 < opcodeEnd); - guint32 mibcGroupMethodEntryToken = read32 (opcodeIp + 1); + g_assert (cur + 4 < end); // Assert that there is atleast a 32 bit token before the end + guint32 mibcGroupMethodEntryToken = read32 (cur + 1); g_assertf ((mono_metadata_token_table (mibcGroupMethodEntryToken) == MONO_TABLE_MEMBERREF || mono_metadata_token_table (mibcGroupMethodEntryToken) == MONO_TABLE_METHODSPEC), "token %x is not MemberRef or MethodSpec.\n", mibcGroupMethodEntryToken); + cur += op_size; MonoMethod *methodEntry = mono_get_method_checked (image, mibcGroupMethodEntryToken, mibcModuleClass, context, error); mono_error_assert_ok (error); @@ -13350,6 +13350,109 @@ add_mibc_group_method_methods (MonoAotCompile *acfg, MonoMethod *mibcGroupMethod return count; } +typedef enum { + PARSING_MIBC_CONFIG_NONE, + PARSING_MIBC_CONFIG_RUNTIME_FIELD, +} MibcConfigParserState; + +//--------------------------------------------------------------------------------------- +// +// compatible_mibc_profile_config is responsible for ensuring that the .mibc profile +// used is compatible with Mono. An incompatible .mibc profile contains types that +// cannot be found on Mono, exemplified by a .mibc generated from a .nettrace collected +// from a CoreCLR based app, as it will contain Canon types not found on Mono. If the +// MibcConfig can be found and the associated runtime is not Mono, return false. If there +// is no MibcConfig, consider the .mibc having been generated prior to the introduction of +// the MibcConfig and permit it. +// +// Sample MibcConfig format +// +// Method 'MibcConfig' (#1443) (0x06000001) +// { +// // Code size 49 (0x31) +// .maxstack 8 +// IL_0000: ldstr 0x70000001 // FormatVersion +// IL_0005: ldstr 0x7000001D // 1.0 +// IL_000a: pop +// IL_000b: pop +// IL_000c: ldstr 0x70000025 // Os +// IL_0011: ldstr 0x7000002B // macOS +// IL_0016: pop +// IL_0017: pop +// IL_0018: ldstr 0x70000037 // Arch +// IL_001d: ldstr 0x70000041 // arm64 +// IL_0022: pop +// IL_0023: pop +// IL_0024: ldstr 0x7000004D // Runtime +// IL_0029: ldstr 0x7000005D // Mono (or 4) +// IL_002e: pop +// IL_002f: pop +// IL_0030: ret +// } +// +// Arguments: +// * image - the MonoImage corresponding to the .mibc +// * mibcModuleClass - the MonoClass containing the MibcConfig +// +// Return Value: +// gboolean pertaining to the compatibility of the provided mibc with mono runtime +// + +static gboolean +compatible_mibc_profile_config (MonoImage *image, MonoClass *mibcModuleClass) +{ + ERROR_DECL (error); + + MonoMethod *mibcConfig = mono_class_get_method_from_name_checked (mibcModuleClass, "MibcConfig", 0, 0, error); + mono_error_assert_ok (error); + + // If there is no MibcConfig, assume it was a .mibc generated prior to MibcConfig addition + if (!mibcConfig) + return TRUE; + + MonoMethodHeader *mibcConfigHeader = mono_method_get_header_internal (mibcConfig, error); + mono_error_assert_ok (error); + + gboolean isConfigCompatible = FALSE; + MibcConfigParserState state = PARSING_MIBC_CONFIG_NONE; + const unsigned char *cur = mibcConfigHeader->code; + const unsigned char *end = mibcConfigHeader->code + mibcConfigHeader->code_size; + while (cur < end && !isConfigCompatible) { + MonoOpcodeEnum il_op; + const int op_size = mono_opcode_value_and_size (&cur, end, &il_op); + + // MibcConfig ends with a Ret + if (il_op == MONO_CEE_RET) + break; + + // we only care about args of ldstr, which are 32bits/4bytes + // ldstr arg is cur + 1 + if (il_op != MONO_CEE_LDSTR) { + cur += op_size; + continue; + } + + g_assert (cur + 4 < end); // Assert that there is atleast a 32 bit token before the end + guint32 token = read32 (cur + 1); + cur += op_size; + + char *value = mono_ldstr_utf8 (image, mono_metadata_token_index (token), error); + mono_error_assert_ok (error); + + if (state == PARSING_MIBC_CONFIG_RUNTIME_FIELD) + isConfigCompatible = !strcmp(value, "Mono") || !strcmp(value, "4"); + + if (!strcmp(value, "Runtime")) + state = PARSING_MIBC_CONFIG_RUNTIME_FIELD; + else + state = PARSING_MIBC_CONFIG_NONE; + + g_free (value); + } + + return isConfigCompatible; +} + //--------------------------------------------------------------------------------------- // // add_mibc_profile_methods is the overarching method that adds methods within a .mibc @@ -13357,7 +13460,8 @@ add_mibc_group_method_methods (MonoAotCompile *acfg, MonoMethod *mibcGroupMethod // methods grouped under mibcGroupMethods, which are summarized within the global // function AssemblyDictionary. This method obtains the AssemblyDictionary and iterates // over il opcodes and arguments to retrieve mibcGroupMethods and thereafter calls -// add_mibc_group_method_methods. +// add_mibc_group_method_methods. A .mibc also may contain a MibcConfig, which we +// check for compatibility with mono. // // Sample AssemblyDictionary format // @@ -13389,6 +13493,11 @@ add_mibc_profile_methods (MonoAotCompile *acfg, char *filename) MonoClass *mibcModuleClass = mono_class_from_name_checked (image, "", "", error); mono_error_assert_ok (error); + if (!compatible_mibc_profile_config (image, mibcModuleClass)) { + aot_printf (acfg, "Skipping .mibc profile '%s' as it is not compatible with the mono runtime. The MibcConfig within the .mibc does not record the Runtime flavor 'Mono'.\n", filename); + return; + } + MonoMethod *assemblyDictionary = mono_class_get_method_from_name_checked (mibcModuleClass, "AssemblyDictionary", 0, 0, error); MonoGenericContext *context = mono_method_get_context (assemblyDictionary); mono_error_assert_ok (error); @@ -13397,21 +13506,22 @@ add_mibc_profile_methods (MonoAotCompile *acfg, char *filename) mono_error_assert_ok (error); int count = 0; - uint8_t *cur = (uint8_t*)header->code; - uint8_t *end = (uint8_t*)header->code + header->code_size; + const unsigned char *cur = header->code; + const unsigned char *end = header->code + header->code_size; while (cur < end) { MonoOpcodeEnum il_op; - const unsigned char *opcodeIp = (unsigned char*)cur; - const unsigned char *opcodeEnd = (unsigned char*)end; - cur += mono_opcode_value_and_size (&opcodeIp, opcodeEnd, &il_op); - // opcodeIp gets moved to point at end of opcode - // il opcode arg is opcodeIp + 1 + const int op_size = mono_opcode_value_and_size (&cur, end, &il_op); + // we only care about args of ldtoken's, which are 32bits/4bytes - if (il_op != MONO_CEE_LDTOKEN) + // ldtoken arg is cur + 1 + if (il_op != MONO_CEE_LDTOKEN) { + cur += op_size; continue; + } - g_assert (opcodeIp + 4 < opcodeEnd); - guint32 token = read32 (opcodeIp + 1); + g_assert (cur + 4 < end); // Assert that there is atleast a 32 bit token before the end + guint32 token = read32 (cur + 1); + cur += op_size; MonoMethod *mibcGroupMethod = mono_get_method_checked (image, token, mibcModuleClass, context, error); mono_error_assert_ok (error);