/// <summary> /// Constructs the map from assembly string to its filename. /// /// Roslyn doesn't record the relationship between a filename and its assembly /// information, so we need to retrieve this information manually. /// </summary> private void SetReferencePaths() { foreach (var reference in compilation.References.OfType <PortableExecutableReference>()) { try { var refPath = reference.FilePath; /* This method is significantly faster and more lightweight than using * System.Reflection.Assembly.ReflectionOnlyLoadFrom. It is also allows * loading the same assembly from different locations. */ using var pereader = new System.Reflection.PortableExecutable.PEReader(new FileStream(refPath, FileMode.Open, FileAccess.Read, FileShare.Read)); var metadata = pereader.GetMetadata(); string assemblyIdentity; unsafe { var reader = new System.Reflection.Metadata.MetadataReader(metadata.Pointer, metadata.Length); var def = reader.GetAssemblyDefinition(); assemblyIdentity = reader.GetString(def.Name) + " " + def.Version; } extractor.SetAssemblyFile(assemblyIdentity, refPath); } catch (Exception ex) // lgtm[cs/catch-of-all-exceptions] { extractor.Message(new Message("Exception reading reference file", reference.FilePath, null, ex.StackTrace)); } } }
public SharedTestState() { if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { // COM activation is only supported on Windows return; } ComLibraryFixture = new TestProjectFixture("ComLibrary", RepoDirectories) .EnsureRestored(RepoDirectories.CorehostPackages) .BuildProject(); // Create a .clsidmap from the assembly string clsidMapPath = Path.Combine(BaseDirectory, $"{ ComLibraryFixture.TestProject.AssemblyName }.clsidmap"); using (var assemblyStream = new FileStream(ComLibraryFixture.TestProject.AppDll, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.Read)) using (var peReader = new System.Reflection.PortableExecutable.PEReader(assemblyStream)) { if (peReader.HasMetadata) { MetadataReader reader = peReader.GetMetadataReader(); ClsidMap.Create(reader, clsidMapPath); } } // Use the locally built comhost to create a comhost with the embedded .clsidmap ComHostPath = Path.Combine( ComLibraryFixture.TestProject.BuiltApp.Location, $"{ ComLibraryFixture.TestProject.AssemblyName }.comhost.dll"); ComHost.Create( Path.Combine(RepoDirectories.CorehostPackages, "comhost.dll"), ComHostPath, clsidMapPath); }
public static string GetVersion(string libFolderPath, string libAssembly) { switch (GetVersionType(libFolderPath, libAssembly)) { case VersionType.Unknown: return(""); case VersionType.V1: case VersionType.V2: { using var fs = File.OpenRead(Path.Combine(libFolderPath, libAssembly)); using var peReader = new System.Reflection.PortableExecutable.PEReader(fs); var mdReader = peReader.GetMetadataReader(MetadataReaderOptions.None); var versionVirtualFileAttribute = GetVirtualFileAttribute(mdReader); var attributeReader = mdReader.GetBlobReader(versionVirtualFileAttribute.Value); attributeReader.ReadByte(); attributeReader.ReadByte(); attributeReader.ReadSerializedString(); var xml = attributeReader.ReadSerializedString(); using var xmlReader = new XmlTextReader(new StringReader(xml)); xmlReader.Read(); xmlReader.MoveToAttribute("Value"); return(xmlReader.Value); } case VersionType.V3: { using var fs = File.OpenRead(Path.Combine(libFolderPath, libAssembly)); using var peReader = new System.Reflection.PortableExecutable.PEReader(fs); var mdReader = peReader.GetMetadataReader(MetadataReaderOptions.None); var versionVirtualFileAttribute = GetVirtualFileAttribute(mdReader); var attributeReader = mdReader.GetBlobReader(versionVirtualFileAttribute.Value); attributeReader.ReadByte(); attributeReader.ReadByte(); attributeReader.ReadSerializedString(); var xml = attributeReader.ReadSerializedString(); using var xmlReader = new XmlTextReader(new StringReader(xml)); xmlReader.Read(); xmlReader.ReadToDescendant("Singleplayer"); xmlReader.MoveToAttribute("Value"); return(xmlReader.Value); } case VersionType.V4: { using var fs = File.OpenRead(Path.Combine(libFolderPath, "Version.xml")); using var reader = new StreamReader(fs); var xml = reader.ReadToEnd(); using var xmlReader = new XmlTextReader(new StringReader(xml)); xmlReader.Read(); xmlReader.ReadToDescendant("Singleplayer"); xmlReader.MoveToAttribute("Value"); var split = xmlReader.Value.Split('.', StringSplitOptions.RemoveEmptyEntries); return(string.Join('.', split.Take(split.Length - 1))); } default: return(""); } }
/// <summary> /// Reads the assembly info from a file. /// This uses System.Reflection.Metadata, which is a very performant and low-level /// library. This is very convenient when scanning hundreds of DLLs at a time. /// </summary> /// <param name="filename">The full filename of the assembly.</param> /// <returns>The information about the assembly.</returns> public static AssemblyInfo ReadFromFile(string filename) { var result = new AssemblyInfo() { Filename = filename }; try { /* This method is significantly faster and more lightweight than using * System.Reflection.Assembly.ReflectionOnlyLoadFrom. It also allows * loading the same assembly from different locations. */ using (var pereader = new System.Reflection.PortableExecutable.PEReader(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))) using (var sha1 = new SHA1CryptoServiceProvider()) { var metadata = pereader.GetMetadata(); unsafe { var reader = new System.Reflection.Metadata.MetadataReader(metadata.Pointer, metadata.Length); var def = reader.GetAssemblyDefinition(); // This is how you compute the public key token from the full public key. // The last 8 bytes of the SHA1 of the public key. var publicKey = reader.GetBlobBytes(def.PublicKey); var publicKeyToken = sha1.ComputeHash(publicKey); var publicKeyString = new StringBuilder(); foreach (var b in publicKeyToken.Skip(12).Reverse()) { publicKeyString.AppendFormat("{0:x2}", b); } result.Name = reader.GetString(def.Name); result.Version = def.Version; result.Culture = def.Culture.IsNil ? "neutral" : reader.GetString(def.Culture); result.PublicKeyToken = publicKeyString.ToString(); result.Valid = true; } } } catch (BadImageFormatException) { // The DLL wasn't an assembly -> result.Valid = false. } catch (InvalidOperationException) { // Some other failure -> result.Valid = false. } return(result); }
public SharedTestState() { if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { // COM activation is only supported on Windows return; } using (var assemblyStream = new FileStream(ComLibraryFixture.TestProject.AppDll, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.Read)) using (var peReader = new System.Reflection.PortableExecutable.PEReader(assemblyStream)) { if (peReader.HasMetadata) { string regFreeManifestPath = Path.Combine(BaseDirectory, $"{ ComLibraryFixture.TestProject.AssemblyName }.X.manifest"); MetadataReader reader = peReader.GetMetadataReader(); RegFreeComManifest.CreateManifestFromClsidmap( ComLibraryFixture.TestProject.AssemblyName, Path.GetFileName(ComHostPath), reader.GetAssemblyDefinition().Version.ToString(), ClsidMapPath, regFreeManifestPath, TypeLibraries ); } } string testDirectoryPath = Path.GetDirectoryName(NativeHostPath); string comsxsName = RuntimeInformationExtensions.GetExeFileNameForCurrentPlatform("comsxs"); ComSxsPath = Path.Combine(testDirectoryPath, comsxsName); File.Copy( Path.Combine(RepoDirectories.Artifacts, "corehost_test", comsxsName), ComSxsPath); File.Copy( ComHostPath, Path.Combine(testDirectoryPath, Path.GetFileName(ComHostPath))); File.Copy( ComLibraryFixture.TestProject.AppDll, Path.Combine(testDirectoryPath, Path.GetFileName(ComLibraryFixture.TestProject.AppDll))); File.Copy( ComLibraryFixture.TestProject.DepsJson, Path.Combine(testDirectoryPath, Path.GetFileName(ComLibraryFixture.TestProject.DepsJson))); File.Copy( ComLibraryFixture.TestProject.RuntimeConfigJson, Path.Combine(testDirectoryPath, Path.GetFileName(ComLibraryFixture.TestProject.RuntimeConfigJson))); }
public static LoadedAssembly FromFile(string path) { using (var s = File.OpenRead(path)) using (var pe = new System.Reflection.PortableExecutable.PEReader(s)) { if (!pe.HasMetadata) { return(null); } var holder = new MetadataBlockHolder(pe.GetMetadata()); if (!holder.Reader.IsAssembly) { holder.Dispose(); return(null); } return(new LoadedAssembly(holder)); } }
public SharedTestState() { if (!OperatingSystem.IsWindows()) { // COM activation is only supported on Windows return; } ComLibraryFixture = new TestProjectFixture("ComLibrary", RepoDirectories) .EnsureRestored() .BuildProject(); // Create a .clsidmap from the assembly ClsidMapPath = Path.Combine(BaseDirectory, $"{ ComLibraryFixture.TestProject.AssemblyName }.clsidmap"); using (var assemblyStream = new FileStream(ComLibraryFixture.TestProject.AppDll, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.Read)) using (var peReader = new System.Reflection.PortableExecutable.PEReader(assemblyStream)) { if (peReader.HasMetadata) { MetadataReader reader = peReader.GetMetadataReader(); ClsidMap.Create(reader, ClsidMapPath); } } // Use the locally built comhost to create a comhost with the embedded .clsidmap ComHostPath = Path.Combine( ComLibraryFixture.TestProject.BuiltApp.Location, $"{ ComLibraryFixture.TestProject.AssemblyName }.comhost.dll"); // Include the test type libraries in the ComHost tests. TypeLibraries = new Dictionary <int, string> { { 1, Path.Combine(RepoDirectories.Artifacts, "corehost_test", "Server.tlb") }, { 2, Path.Combine(RepoDirectories.Artifacts, "corehost_test", "Nested.tlb") } }; ComHost.Create( Path.Combine(RepoDirectories.HostArtifacts, "comhost.dll"), ComHostPath, ClsidMapPath, TypeLibraries); }
public static int GetChangeSet(string libFolderPath, string libAssembly) { switch (GetVersionType(libFolderPath, libAssembly)) { case VersionType.Unknown: return(0); case VersionType.V1: return(0); case VersionType.V2: case VersionType.V3: { using var fs = File.OpenRead(Path.Combine(libFolderPath, libAssembly)); using var peReader = new System.Reflection.PortableExecutable.PEReader(fs); var mdReader = peReader.GetMetadataReader(MetadataReaderOptions.None); var changeSetHandle = mdReader.TypeDefinitions .GetType(mdReader, "TaleWorlds.Library", "ApplicationVersion") .GetField(mdReader, "DefaultChangeSet") .GetDefaultValue(); var changeSetBlob = mdReader.GetConstant(changeSetHandle).Value; return(mdReader.GetBlobReader(changeSetBlob).ReadInt32()); } case VersionType.V4: { using var fs = File.OpenRead(Path.Combine(libFolderPath, "Version.xml")); using var reader = new StreamReader(fs); var xml = reader.ReadToEnd(); using var xmlReader = new XmlTextReader(new StringReader(xml)); xmlReader.Read(); xmlReader.ReadToDescendant("Singleplayer"); xmlReader.MoveToAttribute("Value"); var split = xmlReader.Value.Split('.', StringSplitOptions.RemoveEmptyEntries); return(int.Parse(split.Last())); } default: return(0); } }
static int ValidateMIbcData(TypeSystemContext tsc, FileInfo outputFileName, byte[] moduleBytes, IEnumerable <MethodProfileData> methodsToAttemptToPrepare) { var peReader = new System.Reflection.PortableExecutable.PEReader(System.Collections.Immutable.ImmutableArray.Create <byte>(moduleBytes)); var profileData = MIbcProfileParser.ParseMIbcFile(tsc, peReader, null, null); Dictionary <MethodDesc, MethodProfileData> mibcDict = new Dictionary <MethodDesc, MethodProfileData>(); foreach (var mibcData in profileData.GetAllMethodProfileData()) { mibcDict.Add((MethodDesc)(object)mibcData.Method, mibcData); } bool failure = false; if (methodsToAttemptToPrepare.Count() != mibcDict.Count) { Program.PrintError($"Not same count of methods {methodsToAttemptToPrepare.Count()} != {mibcDict.Count}"); failure = true; } foreach (var entry in methodsToAttemptToPrepare) { MethodDesc method = entry.Method; if (!mibcDict.ContainsKey(method)) { Program.PrintError($"{method} not found in mibcEntryData"); failure = true; continue; } } if (failure) { return(-1); } else { Program.PrintMessage($"Validated {outputFileName.FullName}"); return(0); } }
private static Version GetAssemblyVersion(string path) { if (!string.IsNullOrEmpty(path) && File.Exists(path)) { using (var fileStream = File.OpenRead(path)) { using (var peReader = new System.Reflection.PortableExecutable.PEReader(fileStream)) { var mdMemoryBlock = peReader.GetMetadata(); unsafe { var metadataReader = new System.Reflection.Metadata.MetadataReader( mdMemoryBlock.Pointer, mdMemoryBlock.Length); var asmDef = metadataReader.GetAssemblyDefinition(); return(asmDef.Version); } } } } return(null); }
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 MethodMemoryMap( TraceProcess p, TraceTypeSystemContext tsc, TraceRuntimeDescToTypeSystemDesc idParser, int clrInstanceID) { // Capture the addresses of jitted code List <MemoryRegionInfo> infos = new List <MemoryRegionInfo>(); Dictionary <long, MemoryRegionInfo> info = new Dictionary <long, MemoryRegionInfo>(); foreach (var e in p.EventsInProcess.ByEventType <MethodLoadUnloadTraceData>()) { if (e.ClrInstanceID != clrInstanceID) { continue; } MethodDesc method = null; try { method = idParser.ResolveMethodID(e.MethodID); } catch { } if (method != null) { infos.Add(new MemoryRegionInfo { StartAddress = e.MethodStartAddress, EndAddress = e.MethodStartAddress + checked ((uint)e.MethodSize), MethodID = e.MethodID, Method = method, }); } } foreach (var e in p.EventsInProcess.ByEventType <MethodLoadUnloadVerboseTraceData>()) { if (e.ClrInstanceID != clrInstanceID) { continue; } MethodDesc method = null; try { method = idParser.ResolveMethodID(e.MethodID); } catch { } if (method != null) { infos.Add(new MemoryRegionInfo { StartAddress = e.MethodStartAddress, EndAddress = e.MethodStartAddress + checked ((uint)e.MethodSize), MethodID = e.MethodID, Method = method, }); } } var sigProvider = new R2RSignatureTypeProvider(tsc); foreach (var module in p.LoadedModules) { if (module.FilePath == "") { continue; } if (!File.Exists(module.FilePath)) { continue; } try { byte[] image = File.ReadAllBytes(module.FilePath); using (FileStream fstream = new FileStream(module.FilePath, FileMode.Open, FileAccess.Read, FileShare.Read)) { var r2rCheckPEReader = new System.Reflection.PortableExecutable.PEReader(fstream, System.Reflection.PortableExecutable.PEStreamOptions.LeaveOpen); if (!ILCompiler.Reflection.ReadyToRun.ReadyToRunReader.IsReadyToRunImage(r2rCheckPEReader)) { continue; } } var reader = new ILCompiler.Reflection.ReadyToRun.ReadyToRunReader(tsc, module.FilePath); foreach (var methodEntry in reader.GetCustomMethodToRuntimeFunctionMapping <TypeDesc, MethodDesc, R2RSigProviderContext>(sigProvider)) { foreach (var runtimeFunction in methodEntry.Value.RuntimeFunctions) { infos.Add(new MemoryRegionInfo { StartAddress = module.ImageBase + (ulong)runtimeFunction.StartAddress, EndAddress = module.ImageBase + (ulong)runtimeFunction.StartAddress + (uint)runtimeFunction.Size, Method = methodEntry.Key, NativeToILMap = runtimeFunction.DebugInfo != null ? NativeToILMap.FromR2RBounds(runtimeFunction.DebugInfo.BoundsList) : null, }); } } } catch { } } // Can have duplicate events, so pick first for each var byMethodID = infos.GroupBy(i => i.MethodID).ToDictionary(g => g.Key, g => g.First()); foreach (MethodILToNativeMapTraceData e in p.EventsInProcess.ByEventType <MethodILToNativeMapTraceData>()) { if (byMethodID.TryGetValue(e.MethodID, out MemoryRegionInfo inf)) { inf.NativeToILMap = NativeToILMap.FromEvent(e); } } _infos = byMethodID.Values.OrderBy(i => i.StartAddress).ToArray(); _infoKeys = _infos.Select(i => i.StartAddress).ToArray(); #if DEBUG for (int i = 0; i < _infos.Length - 1; i++) { var cur = _infos[i]; var next = _infos[i + 1]; if (cur.EndAddress <= next.StartAddress) { continue; } Debug.Fail("Overlap in memory ranges"); } #endif }
/// <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)); } }
public SharedTestState() { if (!OperatingSystem.IsWindows()) { // COM activation is only supported on Windows return; } string comsxsDirectory = BaseDirectory; string regFreeManifestName = $"{ ComLibraryFixture.TestProject.AssemblyName }.X.manifest"; string regFreeManifestPath = Path.Combine(comsxsDirectory, regFreeManifestName); using (var assemblyStream = new FileStream(ComLibraryFixture.TestProject.AppDll, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.Read)) using (var peReader = new System.Reflection.PortableExecutable.PEReader(assemblyStream)) { if (peReader.HasMetadata) { MetadataReader reader = peReader.GetMetadataReader(); RegFreeComManifest.CreateManifestFromClsidmap( ComLibraryFixture.TestProject.AssemblyName, Path.GetFileName(ComHostPath), reader.GetAssemblyDefinition().Version.ToString(), ClsidMapPath, regFreeManifestPath, TypeLibraries ); } } string comsxsName = RuntimeInformationExtensions.GetExeFileNameForCurrentPlatform("comsxs"); ComSxsPath = Path.Combine(comsxsDirectory, comsxsName); File.Copy( Path.Combine(RepoDirectories.Artifacts, "corehost_test", comsxsName), ComSxsPath); ManagedHostFixture_FrameworkDependent = new TestProjectFixture("ManagedHost", RepoDirectories) .EnsureRestored() .PublishProject(selfContained: false, extraArgs: "/p:RegFreeCom=true"); File.Copy(regFreeManifestPath, Path.Combine(ManagedHostFixture_FrameworkDependent.TestProject.BuiltApp.Location, regFreeManifestName)); ManagedHostFixture_SelfContained = new TestProjectFixture("ManagedHost", RepoDirectories) .EnsureRestored() .PublishProject(selfContained: true, extraArgs: "/p:RegFreeCom=true"); File.Copy(regFreeManifestPath, Path.Combine(ManagedHostFixture_SelfContained.TestProject.BuiltApp.Location, regFreeManifestName)); // Copy the ComLibrary output and comhost to the ComSxS and ManagedHost directories string[] toCopy = { ComLibraryFixture.TestProject.AppDll, ComLibraryFixture.TestProject.DepsJson, ComLibraryFixture.TestProject.RuntimeConfigJson, ComHostPath, }; foreach (string filePath in toCopy) { File.Copy(filePath, Path.Combine(comsxsDirectory, Path.GetFileName(filePath))); File.Copy(filePath, Path.Combine(ManagedHostFixture_FrameworkDependent.TestProject.BuiltApp.Location, Path.GetFileName(filePath))); File.Copy(filePath, Path.Combine(ManagedHostFixture_SelfContained.TestProject.BuiltApp.Location, Path.GetFileName(filePath))); } }
public MethodMemoryMap( TraceProcess p, TraceTypeSystemContext tsc, TraceRuntimeDescToTypeSystemDesc idParser, int clrInstanceID, FileInfo preciseDebugInfoFile, Logger logger) { // Capture the addresses of jitted code List <MemoryRegionInfo> infos = new List <MemoryRegionInfo>(); Dictionary <JittedID, MemoryRegionInfo> info = new Dictionary <JittedID, MemoryRegionInfo>(); foreach (var e in p.EventsInProcess.ByEventType <MethodLoadUnloadTraceData>()) { if (e.ClrInstanceID != clrInstanceID) { continue; } MethodDesc method = null; try { method = idParser.ResolveMethodID(e.MethodID); } catch { } if (method != null) { JittedID jittedID = new JittedID(e.MethodID, 0); if (!info.ContainsKey(jittedID)) { info.Add(jittedID, new MemoryRegionInfo { StartAddress = e.MethodStartAddress, EndAddress = e.MethodStartAddress + checked ((uint)e.MethodSize), Method = method, }); } } } foreach (var e in p.EventsInProcess.ByEventType <MethodLoadUnloadVerboseTraceData>()) { if (e.ClrInstanceID != clrInstanceID) { continue; } MethodDesc method = null; try { method = idParser.ResolveMethodID(e.MethodID, throwIfNotFound: false); } catch { } if (method != null) { JittedID jittedID = new JittedID(e.MethodID, e.ReJITID); if (!info.ContainsKey(jittedID)) { info.Add(jittedID, new MemoryRegionInfo { StartAddress = e.MethodStartAddress, EndAddress = e.MethodStartAddress + checked ((uint)e.MethodSize), Method = method, }); } } } var sigProvider = new R2RSignatureTypeProviderForGlobalTables(tsc); foreach (var module in p.LoadedModules) { if (module.FilePath == "") { continue; } if (!File.Exists(module.FilePath)) { continue; } try { byte[] image = File.ReadAllBytes(module.FilePath); using (FileStream fstream = new FileStream(module.FilePath, FileMode.Open, FileAccess.Read, FileShare.Read)) { var r2rCheckPEReader = new System.Reflection.PortableExecutable.PEReader(fstream, System.Reflection.PortableExecutable.PEStreamOptions.LeaveOpen); if (!ILCompiler.Reflection.ReadyToRun.ReadyToRunReader.IsReadyToRunImage(r2rCheckPEReader)) { continue; } } var reader = new ILCompiler.Reflection.ReadyToRun.ReadyToRunReader(tsc, module.FilePath); foreach (var methodEntry in reader.GetCustomMethodToRuntimeFunctionMapping <TypeDesc, MethodDesc, R2RSigProviderContext>(sigProvider)) { foreach (var runtimeFunction in methodEntry.Value.RuntimeFunctions) { infos.Add(new MemoryRegionInfo { StartAddress = module.ImageBase + (ulong)runtimeFunction.StartAddress, EndAddress = module.ImageBase + (ulong)runtimeFunction.StartAddress + (uint)runtimeFunction.Size, Method = methodEntry.Key, NativeToILMap = runtimeFunction.DebugInfo != null ? CreateNativeToILMap(methodEntry.Key, runtimeFunction.DebugInfo.BoundsList) : null, }); } } } catch { logger.PrintWarning($"Failed to load method entry points from R2R module {module.FilePath}"); } } List <PreciseDebugInfo> preciseInfos = null; if (preciseDebugInfoFile != null) { preciseInfos = File.ReadAllLines(preciseDebugInfoFile.FullName) .Select(l => JsonSerializer.Deserialize <PreciseDebugInfo>(l)) .ToList(); } if (preciseInfos != null && preciseInfos.Count > 0) { foreach (PreciseDebugInfo preciseDebugInf in preciseInfos) { if (info.TryGetValue(new JittedID((long)preciseDebugInf.MethodID, 0), out MemoryRegionInfo inf)) { inf.NativeToILMap = CreateNativeToILMap(idParser, preciseDebugInf); } } } else { // Associate NativeToILMap with MethodLoad event found Memory Regions foreach (MethodILToNativeMapTraceData e in p.EventsInProcess.ByEventType <MethodILToNativeMapTraceData>()) { if (info.TryGetValue(new JittedID(e.MethodID, e.ReJITID), out MemoryRegionInfo inf)) { inf.NativeToILMap = CreateNativeToILMap(inf.Method, e); } } } // Sort the R2R data by StartAddress MemoryRegionInfoStartAddressComparer startAddressComparer = new MemoryRegionInfoStartAddressComparer(); infos.Sort(startAddressComparer); // For each method found via MethodLoad events, check to see if it exists in the infos array, and if it does not, build a list to add List <MemoryRegionInfo> memoryRegionsToAdd = new List <MemoryRegionInfo>(); foreach (var methodLoadInfo in info.Values) { int searchResult = infos.BinarySearch(methodLoadInfo, startAddressComparer); if (searchResult < 0) { memoryRegionsToAdd.Add(methodLoadInfo); } } // Add the regions from the MethodLoad events, and keep the overall array sorted infos.AddRange(memoryRegionsToAdd); infos.Sort(startAddressComparer); _infos = infos.ToArray(); _infoKeys = _infos.Select(i => i.StartAddress).ToArray(); #if DEBUG for (int i = 0; i < _infos.Length - 1; i++) { var cur = _infos[i]; var next = _infos[i + 1]; if (cur.EndAddress <= next.StartAddress) { continue; } Debug.Fail("Overlap in memory ranges"); } #endif }
public static VersionType GetVersionType(string libFolderPath, string libAssembly) { if (File.Exists(Path.Combine(libFolderPath, "Version.xml"))) { return(VersionType.V4); } using var fs = File.OpenRead(Path.Combine(libFolderPath, libAssembly)); using var peReader = new System.Reflection.PortableExecutable.PEReader(fs); var mdReader = peReader.GetMetadataReader(MetadataReaderOptions.None); var applicationVersionDef = mdReader.TypeDefinitions .GetType(mdReader, "TaleWorlds.Library", "ApplicationVersion"); var hasChangeSet = applicationVersionDef.GetFields() .Any(f => mdReader.GetString(mdReader.GetFieldDefinition(f).Name) == "DefaultChangeSet"); var versionVirtualFileAttribute = GetVirtualFileAttribute(mdReader); var attributeReader = mdReader.GetBlobReader(versionVirtualFileAttribute.Value); if (attributeReader.ReadByte() != 0x01 || attributeReader.ReadByte() != 0x00) { throw new NotImplementedException("Custom Attribute prolog is invalid."); } var fn = attributeReader.ReadSerializedString(); if (fn != "Version.xml") { throw new NotImplementedException("Version field doesn't have Version.xml attribute."); } var xml = attributeReader.ReadSerializedString(); using var xmlReader = new XmlTextReader(new StringReader(xml)); if (!xmlReader.Read()) { throw new NotImplementedException("Can't parse XML content of Version.xml"); } if (hasChangeSet) { if (!xmlReader.MoveToAttribute("Value")) { if (!xmlReader.ReadToDescendant("Singleplayer")) { return(VersionType.Unknown); } return(VersionType.V3); } return(VersionType.V2); } else { if (!xmlReader.MoveToAttribute("Value")) { return(VersionType.Unknown); } return(VersionType.V1); } }