public EcmaModule GetModuleFromPath(string filePath) { // This is called once for every assembly that should be verified, so linear search is acceptable. foreach (KeyValuePair <EcmaModule, ModuleData> entry in _moduleData) { EcmaModule curModule = entry.Key; ModuleData curData = entry.Value; if (curData.Path == filePath) { return(curModule); } } PEReader peReader = new PEReader(File.OpenRead(filePath)); EcmaModule module = EcmaModule.Create(this, peReader); MetadataReader metadataReader = module.MetadataReader; string simpleName = metadataReader.GetString(metadataReader.GetAssemblyDefinition().Name); if (_modules.ContainsKey(simpleName)) { throw new CommandLineException("Module with same simple name already exists " + filePath); } _modules.Add(simpleName, module); ModuleData moduleData = new ModuleData() { Path = filePath }; _moduleData.Add(module, moduleData); return(module); }
private EcmaModule CreateModuleForSimpleName(string simpleName) { string filePath; if (!InputFilePaths.TryGetValue(simpleName, out filePath)) { if (!ReferenceFilePaths.TryGetValue(simpleName, out filePath)) { throw new CommandLineException("Assembly not found: " + simpleName); } } PEReader peReader = new PEReader(File.OpenRead(filePath)); EcmaModule module = EcmaModule.Create(this, peReader); MetadataReader metadataReader = module.MetadataReader; string actualSimpleName = metadataReader.GetString(metadataReader.GetAssemblyDefinition().Name); if (!actualSimpleName.Equals(simpleName, StringComparison.OrdinalIgnoreCase)) { throw new CommandLineException("Assembly name does not match filename " + filePath); } _modules.Add(simpleName, module); ModuleData moduleData = new ModuleData() { Path = filePath }; _moduleData.Add(module, moduleData); return(module); }
private EcmaModule AddModule(string filePath, string expectedSimpleName) { MemoryMappedViewAccessor mappedViewAccessor = null; PdbSymbolReader pdbReader = null; try { PEReader peReader = OpenPEFile(filePath, out mappedViewAccessor); pdbReader = OpenAssociatedSymbolFile(filePath); EcmaModule module = EcmaModule.Create(this, peReader, pdbReader); MetadataReader metadataReader = module.MetadataReader; string simpleName = metadataReader.GetString(metadataReader.GetAssemblyDefinition().Name); if (expectedSimpleName != null && !simpleName.Equals(expectedSimpleName, StringComparison.OrdinalIgnoreCase)) { throw new FileNotFoundException("Assembly name does not match filename " + filePath); } ModuleData moduleData = new ModuleData() { SimpleName = simpleName, FilePath = filePath, Module = module, MappedViewAccessor = mappedViewAccessor }; lock (this) { ModuleData actualModuleData = _simpleNameHashtable.AddOrGetExisting(moduleData); if (actualModuleData != moduleData) { if (actualModuleData.FilePath != filePath) { throw new FileNotFoundException("Module with same simple name already exists " + filePath); } return(actualModuleData.Module); } mappedViewAccessor = null; // Ownership has been transfered pdbReader = null; // Ownership has been transferred _moduleHashtable.AddOrGetExisting(moduleData); } return(module); } finally { if (mappedViewAccessor != null) { mappedViewAccessor.Dispose(); } if (pdbReader != null) { pdbReader.Dispose(); } } }
private EcmaModule AddModule(string filePath, string expectedSimpleName, byte[] moduleDataBytes, bool useForBinding) { MemoryMappedViewAccessor mappedViewAccessor = null; PdbSymbolReader pdbReader = null; try { PEReader peReader = OpenPEFile(filePath, moduleDataBytes, out mappedViewAccessor); pdbReader = OpenAssociatedSymbolFile(filePath, peReader); EcmaModule module = EcmaModule.Create(this, peReader, containingAssembly: null, pdbReader); MetadataReader metadataReader = module.MetadataReader; string simpleName = metadataReader.GetString(metadataReader.GetAssemblyDefinition().Name); ModuleData moduleData = new ModuleData() { SimpleName = simpleName, FilePath = filePath, Module = module, MappedViewAccessor = mappedViewAccessor }; lock (this) { if (useForBinding) { ModuleData actualModuleData = _simpleNameHashtable.AddOrGetExisting(moduleData); if (actualModuleData != moduleData) { if (actualModuleData.FilePath != filePath) { throw new FileNotFoundException("Module with same simple name already exists " + filePath); } return(actualModuleData.Module); } } mappedViewAccessor = null; // Ownership has been transfered pdbReader = null; // Ownership has been transferred _moduleHashtable.AddOrGetExisting(moduleData); } return(module); } finally { if (mappedViewAccessor != null) { mappedViewAccessor.Dispose(); } if (pdbReader != null) { pdbReader.Dispose(); } } }
public static MibcConfig ParseMibcConfig(TypeSystemContext tsc, PEReader pEReader) { EcmaModule mibcModule = EcmaModule.Create(tsc, pEReader, null); EcmaMethod mibcConfigMth = (EcmaMethod)mibcModule.GetGlobalModuleType().GetMethod(nameof(MibcConfig), null); if (mibcConfigMth == null) { return(null); } var ilBody = EcmaMethodIL.Create(mibcConfigMth); var ilReader = new ILReader(ilBody.GetILBytes()); // Parse: // // ldstr "key1" // ldstr "value1" // pop // pop // ldstr "key2" // ldstr "value2" // pop // pop // ... // ret string fieldName = null; Dictionary <string, string> keyValue = new(); while (ilReader.HasNext) { ILOpcode opcode = ilReader.ReadILOpcode(); switch (opcode) { case ILOpcode.ldstr: var ldStrValue = (string)ilBody.GetObject(ilReader.ReadILToken()); if (fieldName != null) { keyValue[fieldName] = ldStrValue; } else { fieldName = ldStrValue; } break; case ILOpcode.ret: case ILOpcode.pop: fieldName = null; break; default: throw new InvalidOperationException($"Unexpected opcode: {opcode}"); } } return(MibcConfig.FromKeyValueMap(keyValue)); }
public EcmaModule CreateModuleForSimpleName(string simpleName) { EcmaModule module = null; try { module = EcmaModule.Create(this, new PEReader(File.OpenRead(simpleName + ".dll"))); } catch (FileNotFoundException) { // FileNotFound is treated as being unable to load the module } _modules.Add(simpleName, module); return(module); }
internal EcmaModule GetModule(PEReader peReader) { if (peReader == null) { return(null); } if (_modulesCache.TryGetValue(peReader, out EcmaModule existingModule)) { return(existingModule); } EcmaModule module = EcmaModule.Create(this, peReader); _modulesCache.Add(peReader, module); return(module); }
internal EcmaModule GetModule(PEReader peReader, IAssemblyDesc containingAssembly = null) { if (peReader == null) { return(null); } if (_modulesCache.TryGetValue(peReader, out EcmaModule existingModule)) { if (containingAssembly != null && existingModule.Assembly != containingAssembly) { throw new VerifierException($"Containing assembly for module '{existingModule}' must be '{containingAssembly}'"); } return(existingModule); } EcmaModule module = EcmaModule.Create(this, peReader, containingAssembly); _modulesCache.Add(peReader, module); return(module); }
static IEnumerable <MIbcData> ReadMIbcData(TraceTypeSystemContext tsc, FileInfo outputFileName, byte[] moduleBytes) { var peReader = new System.Reflection.PortableExecutable.PEReader(System.Collections.Immutable.ImmutableArray.Create <byte>(moduleBytes)); var module = EcmaModule.Create(tsc, peReader, null, null, new CustomCanonResolver(tsc)); var loadedMethod = (EcmaMethod)module.GetGlobalModuleType().GetMethod("AssemblyDictionary", null); EcmaMethodIL ilBody = EcmaMethodIL.Create(loadedMethod); byte[] ilBytes = ilBody.GetILBytes(); int currentOffset = 0; while (currentOffset < ilBytes.Length) { ILOpcode opcode = (ILOpcode)ilBytes[currentOffset]; if (opcode == ILOpcode.prefix1) { opcode = 0x100 + (ILOpcode)ilBytes[currentOffset + 1]; } switch (opcode) { case ILOpcode.ldtoken: UInt32 token = (UInt32)(ilBytes[currentOffset + 1] + (ilBytes[currentOffset + 2] << 8) + (ilBytes[currentOffset + 3] << 16) + (ilBytes[currentOffset + 4] << 24)); foreach (var data in ReadMIbcGroup(tsc, (EcmaMethod)ilBody.GetObject((int)token))) { yield return(data); } break; case ILOpcode.pop: break; } // This isn't correct if there is a switch opcode, but since we won't do that, its ok currentOffset += opcode.GetSize(); } GC.KeepAlive(peReader); }
public EcmaModule GetModuleFromPath(string filePath) { PEReader peReader = new PEReader(File.OpenRead(filePath)); EcmaModule module = EcmaModule.Create(this, peReader); MetadataReader metadataReader = module.MetadataReader; string simpleName = metadataReader.GetString(metadataReader.GetAssemblyDefinition().Name); if (_modules.ContainsKey(simpleName)) { throw new CommandLineException("Module with same simple name already exists " + filePath); } _modules.Add(simpleName, module); ModuleData moduleData = new ModuleData() { Path = filePath }; _moduleData.Add(module, moduleData); return(module); }
/// <summary> /// Parse an MIBC file for the methods that are interesting. /// The version bubble must be specified and will describe the restrict the set of methods parsed to those relevant to the compilation /// The onlyDefinedInAssembly parameter is used to restrict the set of types parsed to include only those which are defined in a specific module. Specify null to allow definitions from all modules. /// This limited parsing is not necessarily an exact set of prevention, so detailed algorithms that work at the individual method level are still necessary, but this allows avoiding excessive parsing. /// /// The format of the Mibc file is that of a .NET dll, with a global method named "AssemblyDictionary". Inside of that file are a series of references that are broken up by which assemblies define the individual methods. /// These references are encoded as IL code that represents the details. /// The format of these IL instruction is as follows. /// /// ldstr mibcGroupName /// ldtoken mibcGroupMethod /// pop /// {Repeat the above pattern N times, once per Mibc group} /// /// See comment above ReadMIbcGroup for details of the group format /// /// The mibcGroupName is in the following format "Assembly_{definingAssemblyName};{OtherAssemblyName};{OtherAssemblyName};...; (OtherAssemblyName is ; delimited) /// /// </summary> /// <returns></returns> public static ProfileData ParseMIbcFile(TypeSystemContext tsc, PEReader peReader, HashSet <string> assemblyNamesInVersionBubble, string onlyDefinedInAssembly) { var mibcModule = EcmaModule.Create(tsc, peReader, null, null, new CustomCanonResolver(tsc)); var assemblyDictionary = (EcmaMethod)mibcModule.GetGlobalModuleType().GetMethod("AssemblyDictionary", null); IEnumerable <MethodProfileData> loadedMethodProfileData = Enumerable.Empty <MethodProfileData>(); EcmaMethodIL ilBody = EcmaMethodIL.Create(assemblyDictionary); byte[] ilBytes = ilBody.GetILBytes(); int currentOffset = 0; string mibcGroupName = ""; while (currentOffset < ilBytes.Length) { ILOpcode opcode = (ILOpcode)ilBytes[currentOffset]; if (opcode == ILOpcode.prefix1) { opcode = 0x100 + (ILOpcode)ilBytes[currentOffset + 1]; } switch (opcode) { case ILOpcode.ldstr: Debug.Assert(mibcGroupName == ""); if (mibcGroupName == "") { UInt32 userStringToken = BinaryPrimitives.ReadUInt32LittleEndian(ilBytes.AsSpan(currentOffset + 1)); mibcGroupName = (string)ilBody.GetObject((int)userStringToken); } break; case ILOpcode.ldtoken: if (String.IsNullOrEmpty(mibcGroupName)) { break; } string[] assembliesByName = mibcGroupName.Split(';'); bool hasMatchingDefinition = (onlyDefinedInAssembly == null) || assembliesByName[0].Equals(onlyDefinedInAssembly); if (!hasMatchingDefinition) { break; } if (assemblyNamesInVersionBubble != null) { bool areAllEntriesInVersionBubble = true; foreach (string s in assembliesByName) { if (string.IsNullOrEmpty(s)) { continue; } if (!assemblyNamesInVersionBubble.Contains(s)) { areAllEntriesInVersionBubble = false; break; } } if (!areAllEntriesInVersionBubble) { break; } } uint token = BinaryPrimitives.ReadUInt32LittleEndian(ilBytes.AsSpan(currentOffset + 1)); loadedMethodProfileData = loadedMethodProfileData.Concat(ReadMIbcGroup(tsc, (EcmaMethod)ilBody.GetObject((int)token))); break; case ILOpcode.pop: mibcGroupName = ""; break; } // This isn't correct if there is a switch opcode, but since we won't do that, its ok currentOffset += opcode.GetSize(); } return(new IBCProfileData(false, loadedMethodProfileData)); }
/// <summary> /// Parse an MIBC file for the methods that are interesting. /// The version bubble must be specified and will describe the restrict the set of methods parsed to those relevant to the compilation /// The onlyDefinedInAssembly parameter is used to restrict the set of types parsed to include only those which are defined in a specific module. Specify null to allow definitions from all modules. /// This limited parsing is not necessarily an exact set of prevention, so detailed algorithms that work at the individual method level are still necessary, but this allows avoiding excessive parsing. /// /// The format of the Mibc file is that of a .NET dll, with a global method named "AssemblyDictionary". Inside of that file are a series of references that are broken up by which assemblies define the individual methods. /// These references are encoded as IL code that represents the details. /// The format of these IL instruction is as follows. /// /// ldstr mibcGroupName /// ldtoken mibcGroupMethod /// pop /// {Repeat the above pattern N times, once per Mibc group} /// /// See comment above ReadMIbcGroup for details of the group format /// /// The mibcGroupName is in the following format "Assembly_{definingAssemblyName};{OtherAssemblyName};{OtherAssemblyName};...; (OtherAssemblyName is ; delimited) /// /// </summary> /// <returns></returns> public static ProfileData ParseMIbcFile(CompilerTypeSystemContext tsc, string filename, HashSet <string> assemblyNamesInVersionBubble, string onlyDefinedInAssembly) { byte[] peData; using (var zipFile = ZipFile.OpenRead(filename)) { var mibcDataEntry = zipFile.GetEntry(Path.GetFileName(filename) + ".dll"); using (var mibcDataStream = mibcDataEntry.Open()) { peData = new byte[mibcDataEntry.Length]; using (BinaryReader br = new BinaryReader(mibcDataStream)) { peData = br.ReadBytes(checked ((int)mibcDataEntry.Length)); } } } using (var peReader = new System.Reflection.PortableExecutable.PEReader(System.Collections.Immutable.ImmutableArray.Create <byte>(peData))) { var mibcModule = EcmaModule.Create(tsc, peReader, null, null, new CustomCanonResolver(tsc)); var assemblyDictionary = (EcmaMethod)mibcModule.GetGlobalModuleType().GetMethod("AssemblyDictionary", null); IEnumerable <MethodProfileData> loadedMethodProfileData = Enumerable.Empty <MethodProfileData>(); EcmaMethodIL ilBody = EcmaMethodIL.Create(assemblyDictionary); byte[] ilBytes = ilBody.GetILBytes(); int currentOffset = 0; string mibcGroupName = ""; while (currentOffset < ilBytes.Length) { ILOpcode opcode = (ILOpcode)ilBytes[currentOffset]; if (opcode == ILOpcode.prefix1) { opcode = 0x100 + (ILOpcode)ilBytes[currentOffset + 1]; } switch (opcode) { case ILOpcode.ldstr: if (mibcGroupName == "") { UInt32 userStringToken = (UInt32)(ilBytes[currentOffset + 1] + (ilBytes[currentOffset + 2] << 8) + (ilBytes[currentOffset + 3] << 16) + (ilBytes[currentOffset + 4] << 24)); mibcGroupName = (string)ilBody.GetObject((int)userStringToken); } break; case ILOpcode.ldtoken: if (String.IsNullOrEmpty(mibcGroupName)) { break; } string[] assembliesByName = mibcGroupName.Split(';'); bool hasMatchingDefinition = (onlyDefinedInAssembly == null) || assembliesByName[0].Equals(onlyDefinedInAssembly); if (!hasMatchingDefinition) { break; } bool areAllEntriesInVersionBubble = true; foreach (string s in assembliesByName) { if (string.IsNullOrEmpty(s)) { continue; } if (!assemblyNamesInVersionBubble.Contains(s)) { areAllEntriesInVersionBubble = false; break; } } if (!areAllEntriesInVersionBubble) { break; } uint token = (uint)(ilBytes[currentOffset + 1] + (ilBytes[currentOffset + 2] << 8) + (ilBytes[currentOffset + 3] << 16) + (ilBytes[currentOffset + 4] << 24)); loadedMethodProfileData = loadedMethodProfileData.Concat(ReadMIbcGroup(tsc, (EcmaMethod)ilBody.GetObject((int)token))); break; case ILOpcode.pop: mibcGroupName = ""; break; } // This isn't correct if there is a switch opcode, but since we won't do that, its ok currentOffset += opcode.GetSize(); } return(new IBCProfileData(false, loadedMethodProfileData)); } }
private EcmaModule AddModule(string filePath, string expectedSimpleName, bool useForBinding, ModuleData oldModuleData = null, bool throwOnFailureToLoad = true) { filePath = Path.GetFullPath(filePath); PEReader peReader = null; MemoryMappedViewAccessor mappedViewAccessor = null; PdbSymbolReader pdbReader = null; try { if (oldModuleData == null) { peReader = OpenPEFile(filePath, out mappedViewAccessor); #if !READYTORUN if (peReader.HasMetadata && (peReader.PEHeaders.CorHeader.Flags & (CorFlags.ILLibrary | CorFlags.ILOnly)) == 0) { throw new NotSupportedException($"Error: C++/CLI is not supported: '{filePath}'"); } #endif pdbReader = PortablePdbSymbolReader.TryOpenEmbedded(peReader, GetMetadataStringDecoder()) ?? OpenAssociatedSymbolFile(filePath, peReader); } else { filePath = oldModuleData.FilePath; peReader = oldModuleData.Module.PEReader; mappedViewAccessor = oldModuleData.MappedViewAccessor; pdbReader = oldModuleData.Module.PdbReader; } if (!peReader.HasMetadata && !throwOnFailureToLoad) { return(null); } EcmaModule module = EcmaModule.Create(this, peReader, containingAssembly: null, pdbReader); MetadataReader metadataReader = module.MetadataReader; string simpleName = metadataReader.GetString(metadataReader.GetAssemblyDefinition().Name); if (expectedSimpleName != null && !simpleName.Equals(expectedSimpleName, StringComparison.OrdinalIgnoreCase)) { throw new FileNotFoundException("Assembly name does not match filename " + filePath); } ModuleData moduleData = new ModuleData() { SimpleName = simpleName, FilePath = filePath, Module = module, MappedViewAccessor = mappedViewAccessor }; lock (this) { if (useForBinding) { ModuleData actualModuleData = _simpleNameHashtable.AddOrGetExisting(moduleData); if (actualModuleData != moduleData) { if (actualModuleData.FilePath != filePath) { throw new FileNotFoundException("Module with same simple name already exists " + filePath); } return(actualModuleData.Module); } } mappedViewAccessor = null; // Ownership has been transfered pdbReader = null; // Ownership has been transferred _moduleHashtable.AddOrGetExisting(moduleData); } return(module); } finally { if (mappedViewAccessor != null) { mappedViewAccessor.Dispose(); } if (pdbReader != null) { pdbReader.Dispose(); } } }
/// <summary> /// Parse an MIBC file for the methods that are interesting. /// The version bubble must be specified and will describe the restrict the set of methods parsed to those relevant to the compilation /// The onlyDefinedInAssembly parameter is used to restrict the set of types parsed to include only those which are defined in a specific module. Specify null to allow definitions from all modules. /// This limited parsing is not necessarily an exact set of prevention, so detailed algorithms that work at the individual method level are still necessary, but this allows avoiding excessive parsing. /// /// The format of the Mibc file is that of a .NET dll, with a global method named "AssemblyDictionary". Inside of that file are a series of references that are broken up by which assemblies define the individual methods. /// These references are encoded as IL code that represents the details. /// The format of these IL instruction is as follows. /// /// ldstr mibcGroupName /// ldtoken mibcGroupMethod /// pop /// {Repeat the above pattern N times, once per Mibc group} /// /// See comment above ReadMIbcGroup for details of the group format /// /// The mibcGroupName is in the following format "Assembly_{definingAssemblyName};{OtherAssemblyName};{OtherAssemblyName};...; (OtherAssemblyName is ; delimited) /// /// </summary> /// <returns></returns> public static ProfileData ParseMIbcFile(TypeSystemContext tsc, PEReader peReader, HashSet <string> assemblyNamesInVersionBubble, string onlyDefinedInAssembly) { var mibcModule = EcmaModule.Create(tsc, peReader, null, null, new CustomCanonResolver(tsc)); var assemblyDictionary = (EcmaMethod)mibcModule.GetGlobalModuleType().GetMethod("AssemblyDictionary", null); IEnumerable <MethodProfileData> loadedMethodProfileData = Enumerable.Empty <MethodProfileData>(); EcmaMethodIL ilBody = EcmaMethodIL.Create(assemblyDictionary); ILReader ilReader = new ILReader(ilBody.GetILBytes()); string mibcGroupName = ""; while (ilReader.HasNext) { ILOpcode opcode = ilReader.ReadILOpcode(); switch (opcode) { case ILOpcode.ldstr: int userStringToken = ilReader.ReadILToken(); Debug.Assert(mibcGroupName == ""); if (mibcGroupName == "") { mibcGroupName = (string)ilBody.GetObject(userStringToken); } break; case ILOpcode.ldtoken: int token = ilReader.ReadILToken(); if (String.IsNullOrEmpty(mibcGroupName)) { break; } string[] assembliesByName = mibcGroupName.Split(';'); bool hasMatchingDefinition = (onlyDefinedInAssembly == null) || assembliesByName[0].Equals(onlyDefinedInAssembly); if (!hasMatchingDefinition) { break; } if (assemblyNamesInVersionBubble != null) { bool areAllEntriesInVersionBubble = true; foreach (string s in assembliesByName) { if (string.IsNullOrEmpty(s)) { continue; } if (!assemblyNamesInVersionBubble.Contains(s)) { areAllEntriesInVersionBubble = false; break; } } if (!areAllEntriesInVersionBubble) { break; } } loadedMethodProfileData = loadedMethodProfileData.Concat(ReadMIbcGroup(tsc, (EcmaMethod)ilBody.GetObject(token))); break; case ILOpcode.pop: mibcGroupName = ""; break; default: ilReader.Skip(opcode); break; } } return(new IBCProfileData(false, loadedMethodProfileData)); }
/// <summary> /// Parse an MIBC file for the methods that are interesting. /// The version bubble must be specified and will describe the restrict the set of methods parsed to those relevant to the compilation /// The onlyDefinedInAssembly parameter is used to restrict the set of types parsed to include only those which are defined in a specific module. Specify null to allow definitions from all modules. /// This limited parsing is not necessarily an exact set of prevention, so detailed algorithms that work at the individual method level are still necessary, but this allows avoiding excessive parsing. /// /// The format of the Mibc file is that of a .NET dll, with a global method named "AssemblyDictionary". Inside of that file are a series of references that are broken up by which assemblies define the individual methods. /// These references are encoded as IL code that represents the details. /// The format of these IL instruction is as follows. /// /// ldstr mibcGroupName /// ldtoken mibcGroupMethod /// pop /// {Repeat the above pattern N times, once per Mibc group} /// /// See comment above ReadMIbcGroup for details of the group format /// /// The mibcGroupName is in the following format "Assembly_{definingAssemblyName};{OtherAssemblyName};{OtherAssemblyName};...; (OtherAssemblyName is ; delimited) /// /// </summary> /// <returns></returns> public static ProfileData ParseMIbcFile(CompilerTypeSystemContext tsc, string filename, HashSet <string> assemblyNamesInVersionBubble, string onlyDefinedInAssembly) { byte[] peData = null; PEReader unprotectedPeReader = null; { FileStream fsMibcFile = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 0x1000, useAsync: false); bool disposeOnException = true; try { byte firstByte = (byte)fsMibcFile.ReadByte(); byte secondByte = (byte)fsMibcFile.ReadByte(); fsMibcFile.Seek(0, SeekOrigin.Begin); if (firstByte == 0x4d && secondByte == 0x5a) { // Uncompressed Mibc format, starts with 'MZ' prefix like all other PE files unprotectedPeReader = new PEReader(fsMibcFile, PEStreamOptions.Default); disposeOnException = false; } else { using (var zipFile = new ZipArchive(fsMibcFile, ZipArchiveMode.Read, leaveOpen: false, entryNameEncoding: null)) { disposeOnException = false; var mibcDataEntry = zipFile.GetEntry(Path.GetFileName(filename) + ".dll"); using (var mibcDataStream = mibcDataEntry.Open()) { peData = new byte[mibcDataEntry.Length]; using (BinaryReader br = new BinaryReader(mibcDataStream)) { peData = br.ReadBytes(checked ((int)mibcDataEntry.Length)); } } } } } finally { if (disposeOnException) { fsMibcFile.Dispose(); } } } if (peData != null) { unprotectedPeReader = new PEReader(System.Collections.Immutable.ImmutableArray.Create <byte>(peData)); } using (var peReader = unprotectedPeReader) { var mibcModule = EcmaModule.Create(tsc, peReader, null, null, new CustomCanonResolver(tsc)); var assemblyDictionary = (EcmaMethod)mibcModule.GetGlobalModuleType().GetMethod("AssemblyDictionary", null); IEnumerable <MethodProfileData> loadedMethodProfileData = Enumerable.Empty <MethodProfileData>(); EcmaMethodIL ilBody = EcmaMethodIL.Create(assemblyDictionary); byte[] ilBytes = ilBody.GetILBytes(); int currentOffset = 0; string mibcGroupName = ""; while (currentOffset < ilBytes.Length) { ILOpcode opcode = (ILOpcode)ilBytes[currentOffset]; if (opcode == ILOpcode.prefix1) { opcode = 0x100 + (ILOpcode)ilBytes[currentOffset + 1]; } switch (opcode) { case ILOpcode.ldstr: if (mibcGroupName == "") { UInt32 userStringToken = BinaryPrimitives.ReadUInt32LittleEndian(ilBytes.AsSpan(currentOffset + 1)); mibcGroupName = (string)ilBody.GetObject((int)userStringToken); } break; case ILOpcode.ldtoken: if (String.IsNullOrEmpty(mibcGroupName)) { break; } string[] assembliesByName = mibcGroupName.Split(';'); bool hasMatchingDefinition = (onlyDefinedInAssembly == null) || assembliesByName[0].Equals(onlyDefinedInAssembly); if (!hasMatchingDefinition) { break; } bool areAllEntriesInVersionBubble = true; foreach (string s in assembliesByName) { if (string.IsNullOrEmpty(s)) { continue; } if (!assemblyNamesInVersionBubble.Contains(s)) { areAllEntriesInVersionBubble = false; break; } } if (!areAllEntriesInVersionBubble) { break; } uint token = BinaryPrimitives.ReadUInt32LittleEndian(ilBytes.AsSpan(currentOffset + 1)); loadedMethodProfileData = loadedMethodProfileData.Concat(ReadMIbcGroup(tsc, (EcmaMethod)ilBody.GetObject((int)token))); break; case ILOpcode.pop: mibcGroupName = ""; break; } // This isn't correct if there is a switch opcode, but since we won't do that, its ok currentOffset += opcode.GetSize(); } return(new IBCProfileData(false, loadedMethodProfileData)); } }
public static ProfileData ParseMIbcFile(TypeSystemContext tsc, PEReader peReader, HashSet <string> assemblyNamesInVersionBubble, string onlyDefinedInAssembly, MibcGroupParseRules parseRule = MibcGroupParseRules.VersionBubble, HashSet <string> crossModuleInlineModules = null) { if (parseRule == MibcGroupParseRules.VersionBubble) { crossModuleInlineModules = s_EmptyHash; } if (parseRule == MibcGroupParseRules.AllGroups) { assemblyNamesInVersionBubble = null; } if (crossModuleInlineModules == null) { crossModuleInlineModules = s_EmptyHash; } var mibcModule = EcmaModule.Create(tsc, peReader, null, null, new CustomCanonResolver(tsc)); var assemblyDictionary = (EcmaMethod)mibcModule.GetGlobalModuleType().GetMethod("AssemblyDictionary", null); IEnumerable <MethodProfileData> loadedMethodProfileData = Enumerable.Empty <MethodProfileData>(); EcmaMethodIL ilBody = EcmaMethodIL.Create(assemblyDictionary); ILReader ilReader = new ILReader(ilBody.GetILBytes()); string mibcGroupName = ""; while (ilReader.HasNext) { ILOpcode opcode = ilReader.ReadILOpcode(); switch (opcode) { case ILOpcode.ldstr: int userStringToken = ilReader.ReadILToken(); Debug.Assert(mibcGroupName == ""); if (mibcGroupName == "") { mibcGroupName = (string)ilBody.GetObject(userStringToken); } break; case ILOpcode.ldtoken: int token = ilReader.ReadILToken(); if (String.IsNullOrEmpty(mibcGroupName)) { break; } string[] assembliesByName = mibcGroupName.Split(';'); bool hasMatchingDefinition = (onlyDefinedInAssembly == null) || assembliesByName[0].Equals(onlyDefinedInAssembly); if (!hasMatchingDefinition) { break; } if (assemblyNamesInVersionBubble != null) { bool mibcGroupUseable = true; bool someEntryInVersionBubble = false; foreach (string s in assembliesByName) { if (string.IsNullOrEmpty(s)) { continue; } bool entryInVersionBubble = assemblyNamesInVersionBubble.Contains(s); someEntryInVersionBubble = someEntryInVersionBubble || entryInVersionBubble; if (!entryInVersionBubble && !crossModuleInlineModules.Contains(s)) { // If the group references a module that isn't in the version bubble and isn't cross module inlineable, its not useful. mibcGroupUseable = false; break; } } if (!someEntryInVersionBubble && (parseRule == MibcGroupParseRules.VersionBubbleWithCrossModule1)) { mibcGroupUseable = false; } if (!mibcGroupUseable) { break; } } loadedMethodProfileData = loadedMethodProfileData.Concat(ReadMIbcGroup(tsc, (EcmaMethod)ilBody.GetObject(token))); break; case ILOpcode.pop: mibcGroupName = ""; break; default: ilReader.Skip(opcode); break; } } return(new IBCProfileData(ParseMibcConfig(tsc, peReader), false, loadedMethodProfileData)); }