private static void Main(string[] args) { bool removeDirectory; string temporaryDirectory = GetTemporaryDirectory(out removeDirectory); Console.WriteLine("Working directory: {0}", temporaryDirectory); try { IPackageRepository sourceRepository = PackageRepositoryFactory.Default.CreateRepository("https://www.nuget.org/api/v2/"); PackageManager packageManager = new PackageManager(sourceRepository, temporaryDirectory); packageManager.PackageInstalled += HandlePackageInstalled; packageManager.InstallPackage("Microsoft.Bcl.Immutable", SemanticVersion.Parse("1.0.34")); packageManager.InstallPackage("System.Collections.Immutable", SemanticVersion.Parse("1.1.33-beta")); using (PEReader referenceAssembly = new PEReader(File.OpenRead(Path.Combine(temporaryDirectory, "Microsoft.Bcl.Immutable.1.0.34", "lib", "portable-net45+win8+wp8+wpa81", "System.Collections.Immutable.dll")))) { using (PEReader newAssembly = new PEReader(File.OpenRead(Path.Combine(temporaryDirectory, "System.Collections.Immutable.1.1.33-beta", "lib", "portable-net45+win8+wp8+wpa81", "System.Collections.Immutable.dll")))) { Analyzer analyzer = new Analyzer(referenceAssembly, newAssembly, null); analyzer.Run(); } } } finally { if (removeDirectory) Directory.Delete(temporaryDirectory, true); } }
static void Main(string[] args) { if (args.Length == 0 || new[] {"/?", "-?", "-h", "--help"}.Any(x => string.Equals(args[0], x, StringComparison.OrdinalIgnoreCase))) { PrintUsage(); return; } foreach (var fileName in args) { Console.WriteLine(fileName); Console.WriteLine(new string('*', 80)); try { using (var stream = File.OpenRead(fileName)) using (var peFile = new PEReader(stream)) { var metadataReader = peFile.GetMetadataReader(); var visualizer = new MetadataVisualizer(metadataReader, Console.Out); visualizer.Visualize(); } } catch (Exception ex) { Console.WriteLine(ex.Message); } } }
public InspectableAssembly(string filename, ParseContext context) { Stream = File.OpenRead(filename); Pe = new PEReader(Stream); Reader = Pe.GetMetadataReader(); Context = context; }
public static AssemblyIdentity TryGetAssemblyIdentity(string filePath) { try { using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete)) using (var peReader = new PEReader(stream)) { var metadataReader = peReader.GetMetadataReader(); AssemblyDefinition assemblyDefinition = metadataReader.GetAssemblyDefinition(); string name = metadataReader.GetString(assemblyDefinition.Name); Version version = assemblyDefinition.Version; StringHandle cultureHandle = assemblyDefinition.Culture; string cultureName = (!cultureHandle.IsNil) ? metadataReader.GetString(cultureHandle) : null; AssemblyFlags flags = assemblyDefinition.Flags; bool hasPublicKey = (flags & AssemblyFlags.PublicKey) != 0; BlobHandle publicKeyHandle = assemblyDefinition.PublicKey; ImmutableArray<byte> publicKeyOrToken = !publicKeyHandle.IsNil ? metadataReader.GetBlobBytes(publicKeyHandle).AsImmutableOrNull() : default(ImmutableArray<byte>); return new AssemblyIdentity(name, version, cultureName, publicKeyOrToken, hasPublicKey); } } catch { } return null; }
+ sizeof(Int64); // metadata directory private static bool ExecuteCore(string assemblyPath) { if (Directory.Exists(assemblyPath)) { Console.Error.WriteLine($"Expected file, not a directory: {assemblyPath}"); return false; } if (!File.Exists(assemblyPath)) { Console.Error.WriteLine($"File not found: {assemblyPath}"); return false; } using (var stream = OpenFile(assemblyPath, FileMode.Open, FileAccess.ReadWrite, FileShare.Read)) using (var reader = new PEReader(stream)) using (var writer = new BinaryWriter(stream)) { if (!Validate(reader)) { Console.Error.WriteLine($"Unable to sign {assemblyPath}"); return false; } stream.Position = reader.PEHeaders.CorHeaderStartOffset + OffsetFromStartOfCorHeaderToFlags; writer.Write((UInt32)(reader.PEHeaders.CorHeader.Flags | CorFlags.StrongNameSigned)); } return true; }
public PE(string fileName) { FileName = Path.GetFullPath(fileName); Uri = new Uri(FileName); IsPEFile = false; try { _fs = File.OpenRead(FileName); byte byteRead = (byte)_fs.ReadByte(); if (byteRead != 'M') { return; } byteRead = (byte)_fs.ReadByte(); if (byteRead != 'Z') { return; } _fs.Seek(0, SeekOrigin.Begin); _peReader = new PEReader(_fs); PEHeaders = _peReader.PEHeaders; IsPEFile = true; } catch (IOException e) { LoadException = e; } catch (BadImageFormatException e) { LoadException = e; } catch (UnauthorizedAccessException e) { LoadException = e; } if (IsPEFile) { m_pImage = new SafePointer(_peReader.GetEntireImage().GetContent().ToBuilder().ToArray()); if (IsManaged) { _metadataReader = _peReader.GetMetadataReader(); } } }
/// <summary> /// Returns true if the PE file meets all of the pre-conditions to be Open Source Signed. /// Returns false and logs msbuild errors otherwise. /// </summary> private bool Validate(PEReader peReader) { if (!peReader.HasMetadata) { LogError("PE file is not a managed module."); return false; } var mdReader = peReader.GetMetadataReader(); if (!mdReader.IsAssembly) { LogError("PE file is not an assembly."); return false; } CorHeader header = peReader.PEHeaders.CorHeader; if ((header.Flags & CorFlags.StrongNameSigned) == CorFlags.StrongNameSigned) { LogError("PE file is already strong-name signed."); return false; } if ((header.StrongNameSignatureDirectory.Size <= 0) || mdReader.GetAssemblyDefinition().PublicKey.IsNil) { LogError("PE file is not a delay-signed assembly."); return false; } return true; }
public static EcmaModule Create(TypeSystemContext context, PEReader peReader, PdbSymbolReader pdbReader) { MetadataReader metadataReader = CreateMetadataReader(context, peReader); if (metadataReader.IsAssembly) return new EcmaAssembly(context, peReader, metadataReader, pdbReader); else return new EcmaModule(context, peReader, metadataReader, pdbReader); }
public void OpenNativeImage() { using (var reader = new PEReader(File.OpenRead(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "kernel32.dll")))) { Assert.False(reader.HasMetadata); Assert.True(reader.PEHeaders.IsDll); Assert.False(reader.PEHeaders.IsExe); Assert.Throws<InvalidOperationException>(() => reader.GetMetadataReader()); } }
public static ISymUnmanagedReader CreateReader(Stream pdbStream, Stream peStreamOpt = null) { if (peStreamOpt != null) { var peReader = new PEReader(peStreamOpt); return CreateReader(pdbStream, peReader.GetMetadataReader(), peReader); } else { return CreateReader(pdbStream, null, null); } }
public override bool Execute() { if (Assemblies == null || Assemblies.Length == 0) return true; List<ITaskItem> references = new List<ITaskItem>(); List<ITaskItem> nativeLibs = new List<ITaskItem>(); foreach (var assemblyItem in Assemblies) { try { if (!File.Exists(assemblyItem.ItemSpec)) { Log.LogError($"File {assemblyItem.ItemSpec} does not exist, ensure you have built libraries before building the package."); continue; } using (PEReader peReader = new PEReader(new FileStream(assemblyItem.ItemSpec, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.Read))) { MetadataReader reader = peReader.GetMetadataReader(); foreach (var handle in reader.AssemblyReferences) { AssemblyReference reference = reader.GetAssemblyReference(handle); TaskItem referenceItem = new TaskItem(reader.GetString(reference.Name)); assemblyItem.CopyMetadataTo(referenceItem); referenceItem.SetMetadata("Version", reference.Version.ToString()); referenceItem.SetMetadata("AssemblyVersion", reference.Version.ToString()); references.Add(referenceItem); } for (int i = 1, count = reader.GetTableRowCount(TableIndex.ModuleRef); i <= count; i++) { var moduleRef = reader.GetModuleReference(MetadataTokens.ModuleReferenceHandle(i)); var moduleName = reader.GetString(moduleRef.Name); TaskItem nativeLib = new TaskItem(moduleName); assemblyItem.CopyMetadataTo(nativeLib); nativeLibs.Add(nativeLib); } } } catch (InvalidOperationException) { // Ignore invalid assemblies } } ReferencedAssemblies = references.ToArray(); ReferencedNativeLibraries = nativeLibs.ToArray(); return true; }
public void IL_EagerLoad() { var peStream = new MemoryStream(TestResources.Misc.Members); using (var reader = new PEReader(peStream, PEStreamOptions.LeaveOpen | PEStreamOptions.PrefetchMetadata | PEStreamOptions.PrefetchEntireImage)) { var md = reader.GetMetadataReader(); var il = reader.GetMethodBody(md.GetMethodDefinition(MetadataTokens.MethodDefinitionHandle(1)).RelativeVirtualAddress); Assert.Equal(new byte[] { 0, 42 }, il.GetILBytes()); Assert.Equal(8, il.MaxStack); } }
public static ReadOnlyCollection<Message> AnalyzeAssemblies(string referenceAssemblyFile, string newAssemblyFile) { using (PEReader referenceAssembly = new PEReader(File.OpenRead(referenceAssemblyFile))) { using (PEReader newAssembly = new PEReader(File.OpenRead(newAssemblyFile))) { TestMessageLogger logger = new TestMessageLogger(); Analyzer analyzer = new Analyzer(referenceAssembly, newAssembly, logger); analyzer.Run(); return logger.RawMessages; } } }
public override bool Execute() { Log.LogMessage(MessageImportance.High, "About to inspect {0} test assemblies.", TestBinaries.Length); var perfTests = new List<ITaskItem>(); foreach (var testBinary in TestBinaries) { Log.LogMessage(MessageImportance.Low, "Inspecting assembly {0}.", testBinary.ItemSpec); using (var stream = File.OpenRead(testBinary.ItemSpec)) { using (var peFile = new PEReader(stream)) { if(!peFile.HasMetadata){ continue; } var mdReader = peFile.GetMetadataReader(); foreach (var asmRefHandle in mdReader.AssemblyReferences) { var asmRef = mdReader.GetAssemblyReference(asmRefHandle); var asmRefName = mdReader.GetString(asmRef.Name); // if an assembly contains a reference to xunit.performance.core // then it contains at least one performance test. if (string.Compare(asmRefName, "xunit.performance.core", StringComparison.OrdinalIgnoreCase) == 0) { var fileName = (GetFullPaths) ? Path.GetFullPath(testBinary.ItemSpec) : Path.GetFileNameWithoutExtension(testBinary.ItemSpec); perfTests.Add(new TaskItem(fileName)); Log.LogMessage("+ Assembly {0} contains one or more performance tests.", fileName); break; } } } } } if (perfTests.Count > 0) { PerfTestAssemblies = perfTests.ToArray(); Log.LogMessage(MessageImportance.High, "Found {0} assemblies containing performance tests.", perfTests.Count); } else { Log.LogWarning("Didn't find any performance tests."); } return true; }
public void Dispose() { if (_peReader != null) { _peReader.Dispose(); _peReader = null; } if (_fs != null) { _fs.Dispose(); _fs = null; } }
public static AssemblyInfo GetAssemblyInfo(string path) { using (var peReader = new PEReader(new FileStream(path, FileMode.Open, FileAccess.Read))) { var contractReader = peReader.GetMetadataReader(); var assembly = contractReader.GetAssemblyDefinition(); var name = contractReader.GetString(assembly.Name); var version = assembly.Version; var references = GetAssemblyReferences(contractReader); return new AssemblyInfo(path, name, version, references); } }
/// <summary> /// Given a path to an assembly, returns its MVID (Module Version ID). /// May throw. /// </summary> /// <exception cref="IOException">If the file at <paramref name="filePath"/> does not exist or cannot be accessed.</exception> /// <exception cref="BadImageFormatException">If the file is not an assembly or is somehow corrupted.</exception> public static Guid ReadMvid(string filePath) { Debug.Assert(filePath != null); Debug.Assert(PathUtilities.IsAbsolute(filePath)); using (var reader = new PEReader(FileUtilities.OpenRead(filePath))) { var metadataReader = reader.GetMetadataReader(); var mvidHandle = metadataReader.GetModuleDefinition().Mvid; var fileMvid = metadataReader.GetGuid(mvidHandle); return fileMvid; } }
public void EmbeddedPortablePdb() { string source = @" using System; class C { public static void Main() { Console.WriteLine(); } } "; var c = CreateCompilationWithMscorlib(Parse(source, "foo.cs"), options: TestOptions.DebugDll); var peBlob = c.EmitToArray(EmitOptions.Default.WithDebugInformationFormat(DebugInformationFormat.Embedded).WithPdbFilePath(@"a/b/c/d.pdb")); using (var peReader = new PEReader(peBlob)) { var entries = peReader.ReadDebugDirectory(); AssertEx.Equal(new[] { DebugDirectoryEntryType.CodeView, DebugDirectoryEntryType.EmbeddedPortablePdb }, entries.Select(e => e.Type)); var codeView = entries[0]; var embedded = entries[1]; // EmbeddedPortablePdb entry: Assert.Equal(0x0100, embedded.MajorVersion); Assert.Equal(0x0100, embedded.MinorVersion); Assert.Equal(0u, embedded.Stamp); BlobContentId pdbId; using (var embeddedMetadataProvider = peReader.ReadEmbeddedPortablePdbDebugDirectoryData(embedded)) { var mdReader = embeddedMetadataProvider.GetMetadataReader(); AssertEx.Equal(new[] { "foo.cs" }, mdReader.Documents.Select(doc => mdReader.GetString(mdReader.GetDocument(doc).Name))); pdbId = new BlobContentId(mdReader.DebugMetadataHeader.Id); } // CodeView entry: var codeViewData = peReader.ReadCodeViewDebugDirectoryData(codeView); Assert.Equal(0x0100, codeView.MajorVersion); Assert.Equal(0x504D, codeView.MinorVersion); Assert.Equal(pdbId.Stamp, codeView.Stamp); Assert.Equal(pdbId.Guid, codeViewData.Guid); Assert.Equal("d.pdb", codeViewData.Path); } }
public void TestSpansPresentInResource() { var c = CreateCompilationWithMscorlib(Parse(ExampleSource + InstrumentationHelperSource, @"C:\myproject\doc1.cs")); var peImage = c.EmitToArray(EmitOptions.Default.WithInstrumentationKinds(ImmutableArray.Create(InstrumentationKind.TestCoverage))); var peReader = new PEReader(peImage); var reader = DynamicAnalysisDataReader.TryCreateFromPE(peReader, "<DynamicAnalysisData>"); VerifyDocuments(reader, reader.Documents, @"'C:\myproject\doc1.cs' FF-9A-1F-F4-03-A5-A1-F7-8D-CD-00-15-67-0E-BA-F7-23-9D-3F-0F (SHA1)"); Assert.Equal(12, reader.Methods.Length); string[] sourceLines = ExampleSource.Split('\n'); VerifySpans(reader, reader.Methods[0], sourceLines, // Main new SpanResult(5, 4, 9, 5, "public static void Main()"), new SpanResult(7, 8, 7, 31, "Console.WriteLine(123)"), new SpanResult(8, 8, 8, 31, "Console.WriteLine(123)")); VerifySpans(reader, reader.Methods[1], sourceLines, // Fred get new SpanResult(11, 4, 11, 32, "public static int Fred => 3"), new SpanResult(11, 30, 11, 31, "3")); VerifySpans(reader, reader.Methods[2], sourceLines, // Barney new SpanResult(13, 4, 13, 41, "public static int Barney(int x) => x"), new SpanResult(13, 39, 13, 40, "x")); VerifySpans(reader, reader.Methods[3], sourceLines, // Wilma get new SpanResult(17, 8, 17, 26, "get { return 12; }"), new SpanResult(17, 14, 17, 24, "return 12")); VerifySpans(reader, reader.Methods[4], sourceLines, // Wilma set new SpanResult(18, 8, 18, 15, "set { }")); VerifySpans(reader, reader.Methods[5], sourceLines, // Betty get new SpanResult(21, 4, 21, 36, "public static int Betty { get; }"), new SpanResult(21, 30, 21, 34, "get")); VerifySpans(reader, reader.Methods[6], sourceLines, // Pebbles get new SpanResult(23, 4, 23, 43, "public static int Pebbles { get; set; }"), new SpanResult(23, 32, 23, 36, "get")); VerifySpans(reader, reader.Methods[7], sourceLines, // Pebbles set new SpanResult(23, 4, 23, 43, "public static int Pebbles { get; set; }"), new SpanResult(23, 37, 23, 41, "set")); VerifySpans(reader, reader.Methods[8]); }
internal override void RemovePublicSign(string assemblyPath) { using (var stream = new FileStream(assemblyPath, FileMode.Open, FileAccess.ReadWrite, FileShare.Read)) using (var peReader = new PEReader(stream)) using (var writer = new BinaryWriter(stream)) { if (!IsPublicSigned(peReader)) { return; } stream.Position = peReader.PEHeaders.CorHeaderStartOffset + OffsetFromStartOfCorHeaderToFlags; writer.Write((UInt32)(peReader.PEHeaders.CorHeader.Flags | CorFlags.StrongNameSigned)); } }
public void BasicValidation() { using (var peStream = new MemoryStream()) { var ilBuilder = new BlobBuilder(); var metadataBuilder = new MetadataBuilder(); var entryPoint = BasicValidationEmit(metadataBuilder, ilBuilder); WritePEImage(peStream, metadataBuilder, ilBuilder, entryPoint); peStream.Position = 0; var r = new PEReader(peStream); var h = r.PEHeaders; var mdReader = r.GetMetadataReader(); } }
+ sizeof(Int64); // metadata directory private static bool ExecuteCore(string assemblyPath, bool unSign = false, bool force = false) { if (Directory.Exists(assemblyPath)) { Console.Error.WriteLine($"Expected file, not a directory: {assemblyPath}"); return false; } if (!File.Exists(assemblyPath)) { Console.Error.WriteLine($"File not found: {assemblyPath}"); return false; } using (var stream = OpenFile(assemblyPath, FileMode.Open, FileAccess.ReadWrite, FileShare.Read)) using (var reader = new PEReader(stream)) using (var writer = new BinaryWriter(stream)) { var mdReader = ValidateManagedAssemblyAndGetMetadataReader(reader); if (mdReader == null) { Console.Error.WriteLine($"Cannot {(unSign ? "un-sign" : "sign")} {assemblyPath}."); return false; } if (!force && !Validate(reader, mdReader, unSign)) { Console.Error.WriteLine($"Use the -f (force) option to {(unSign ? "un-sign" : "sign")} {assemblyPath} anyway."); return false; } stream.Position = reader.PEHeaders.CorHeaderStartOffset + OffsetFromStartOfCorHeaderToFlags; var flags = reader.PEHeaders.CorHeader.Flags; if (unSign) { flags &= ~CorFlags.StrongNameSigned; } else { flags |= CorFlags.StrongNameSigned; } writer.Write((UInt32)flags); } return true; }
public static ImmutableArray<DebugDirectoryEntry> ReadDebugDirectory(PEReader peReader, Stream peStream) { var debugDirectory = peReader.PEHeaders.PEHeader.DebugTableDirectory; // TODO: Add API to PEReader to get a memory block for a directory int position; if (!peReader.PEHeaders.TryGetDirectoryOffset(debugDirectory, out position)) { throw new BadImageFormatException(); } const int entrySize = 0x1c; if (debugDirectory.Size % entrySize != 0) { throw new BadImageFormatException(); } peStream.Position = position; var reader = new BinaryReader(peStream); int entryCount = debugDirectory.Size / entrySize; var builder = ImmutableArray.CreateBuilder<DebugDirectoryEntry>(entryCount); for (int i = 0; i < entryCount; i++) { // Reserved, must be zero. int characteristics = reader.ReadInt32(); if (characteristics != 0) { throw new BadImageFormatException(); } uint stamp = reader.ReadUInt32(); ushort majorVersion = reader.ReadUInt16(); ushort minorVersion = reader.ReadUInt16(); var type = (DebugDirectoryEntryType)reader.ReadInt32(); int dataSize = reader.ReadInt32(); int dataRva = reader.ReadInt32(); int dataPointer = reader.ReadInt32(); builder.Add(new DebugDirectoryEntry(stamp, majorVersion, minorVersion, type, dataSize, dataRva, dataPointer)); } return builder.MoveToImmutable(); }
/// <summary> /// Returns true if the PE file meets all of the pre-conditions to be Open Source Signed. /// Returns false and logs msbuild errors otherwise. /// </summary> private static bool IsPublicSigned(PEReader peReader) { if (!peReader.HasMetadata) { return false; } var mdReader = peReader.GetMetadataReader(); if (!mdReader.IsAssembly) { return false; } CorHeader header = peReader.PEHeaders.CorHeader; return (header.Flags & CorFlags.StrongNameSigned) == CorFlags.StrongNameSigned; }
public static bool HasMetadata(string pathToFile) { try { using (var inStream = File.OpenRead(pathToFile)) { using (var peReader = new PEReader(inStream)) { return peReader.HasMetadata; } } } catch (BadImageFormatException) { } return false; }
private static unsafe byte[] GetEmbeddedResourceContents(PEReader peReader, ManifestResource resource) { if (!resource.Implementation.IsNil) { throw new ArgumentException("Resource is not embedded in the PE file.", "resource"); } checked // arithmetic overflow here could cause AV { // Locate start and end of PE image in unmanaged memory. var block = peReader.GetEntireImage(); int peImageSize = block.Length; byte* peImageStart = block.Pointer; byte* peImageEnd = peImageStart + peImageSize; Debug.Assert(peImageStart != null && peImageSize > 0); // Locate offset to resources within PE image. int offsetToResources; if (!peReader.PEHeaders.TryGetDirectoryOffset(peReader.PEHeaders.CorHeader.ResourcesDirectory, out offsetToResources)) { throw new InvalidDataException("Failed to get offset to resources in PE file."); } Debug.Assert(offsetToResources > 0); byte* resourceStart = peImageStart + offsetToResources + resource.Offset; // Get the length of the the resource from the first 4 bytes. if (resourceStart >= peImageEnd - sizeof(int)) { throw new InvalidDataException("resource offset out of bounds."); } int resourceLength = *(int*)(resourceStart); resourceStart += sizeof(int); if (resourceLength < 0 || resourceStart >= peImageEnd - resourceLength) { throw new InvalidDataException("resource offset or length out of bounds."); } // TODO: Use UmanagedMemoryStream when available on core clr var buffer = new byte[resourceLength]; for (int i = 0; i < resourceLength; i++) { buffer[i] = *(resourceStart + i); } return buffer; } }
private bool ExecuteCore() { using (var stream = OpenFile(this.AssemblyPath, FileMode.Open, FileAccess.ReadWrite, FileShare.Read)) using (var reader = new PEReader(stream)) using (var writer = new BinaryWriter(stream)) { if (!Validate(reader)) { return false; } stream.Position = reader.PEHeaders.CorHeaderStartOffset + OffsetFromStartOfCorHeaderToFlags; writer.Write((UInt32)(reader.PEHeaders.CorHeader.Flags | CorFlags.StrongNameSigned)); } return true; }
private static MetadataReader ValidateManagedAssemblyAndGetMetadataReader(PEReader peReader) { if (!peReader.HasMetadata) { Console.Error.WriteLine("PE file is not a managed module."); return null; } var mdReader = peReader.GetMetadataReader(); if (!mdReader.IsAssembly) { Console.Error.WriteLine("PE file is not an assembly."); return null; } return mdReader; }
/// <remarks> /// Based on https://gist.github.com/nguerrera/72444715c7ea0b40addb /// </remarks> public static byte[] GetILBytes(this MethodInfo methodInfo) { #if NET45 return methodInfo.GetMethodBody().GetILAsByteArray(); #else var metadataToken = methodInfo.GetMetadataToken(); using (var stream = File.OpenRead(methodInfo.DeclaringType.GetTypeInfo().Assembly.Location)) using (var peReader = new PEReader(stream)) { var metadataReader = peReader.GetMetadataReader(); var methodHandle = MetadataTokens.MethodDefinitionHandle(metadataToken); var methodDefinition = metadataReader.GetMethodDefinition(methodHandle); var methodBody = peReader.GetMethodBody(methodDefinition.RelativeVirtualAddress); return methodBody.GetILBytes(); } #endif }
/// <summary> /// Given a path to an assembly, identifies files in the same directory /// that could satisfy the assembly's dependencies. May throw. /// </summary> /// <remarks> /// Dependencies are identified by simply checking the name of an assembly /// reference against a file name; if they match the file is considered a /// dependency. Other factors, such as version, culture, public key, etc., /// are not considered, and so the returned collection may include items that /// cannot in fact satisfy the original assembly's dependencies. /// </remarks> /// <exception cref="IOException">If the file at <paramref name="filePath"/> does not exist or cannot be accessed.</exception> /// <exception cref="BadImageFormatException">If the file is not an assembly or is somehow corrupted.</exception> public static ImmutableArray<string> FindAssemblySet(string filePath) { Debug.Assert(filePath != null); Debug.Assert(PathUtilities.IsAbsolute(filePath)); Queue<string> workList = new Queue<string>(); HashSet<string> assemblySet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); workList.Enqueue(filePath); while (workList.Count > 0) { string assemblyPath = workList.Dequeue(); if (!assemblySet.Add(assemblyPath)) { continue; } var directory = Path.GetDirectoryName(assemblyPath); using (var reader = new PEReader(FileUtilities.OpenRead(assemblyPath))) { var metadataReader = reader.GetMetadataReader(); var assemblyReferenceHandles = metadataReader.AssemblyReferences; foreach (var handle in assemblyReferenceHandles) { var reference = metadataReader.GetAssemblyReference(handle); var referenceName = metadataReader.GetString(reference.Name); string referencePath = Path.Combine(directory, referenceName + ".dll"); if (!assemblySet.Contains(referencePath) && File.Exists(referencePath)) { workList.Enqueue(referencePath); } } } } return ImmutableArray.CreateRange(assemblySet); }
static int InnerProcessTraceFileMain(CommandLineOptions commandLineOptions) { if (commandLineOptions.TraceFile == null) { PrintUsage(commandLineOptions, "--trace must be specified"); return(-8); } if (commandLineOptions.OutputFileName == null) { PrintUsage(commandLineOptions, "--output must be specified"); return(-8); } if (commandLineOptions.OutputFileName != null) { if (!commandLineOptions.FileType.HasValue) { PrintUsage(commandLineOptions, $"--pgo-file-type must be specified"); return(-9); } if ((commandLineOptions.FileType.Value != PgoFileType.jittrace) && (commandLineOptions.FileType != PgoFileType.mibc)) { PrintUsage(commandLineOptions, $"Invalid output pgo type {commandLineOptions.FileType} specified."); return(-9); } if (commandLineOptions.FileType == PgoFileType.jittrace) { if (!commandLineOptions.OutputFileName.Name.EndsWith(".jittrace")) { PrintUsage(commandLineOptions, $"jittrace output file name must end with .jittrace"); return(-9); } } if (commandLineOptions.FileType == PgoFileType.mibc) { if (!commandLineOptions.OutputFileName.Name.EndsWith(".mibc")) { PrintUsage(commandLineOptions, $"mibc output file name must end with .mibc"); return(-9); } } } string etlFileName = commandLineOptions.TraceFile.FullName; foreach (string nettraceExtension in new string[] { ".netperf", ".netperf.zip", ".nettrace" }) { if (commandLineOptions.TraceFile.FullName.EndsWith(nettraceExtension)) { etlFileName = commandLineOptions.TraceFile.FullName.Substring(0, commandLineOptions.TraceFile.FullName.Length - nettraceExtension.Length) + ".etlx"; PrintMessage($"Creating ETLX file {etlFileName} from {commandLineOptions.TraceFile.FullName}"); TraceLog.CreateFromEventPipeDataFile(commandLineOptions.TraceFile.FullName, etlFileName); } } string lttngExtension = ".trace.zip"; if (commandLineOptions.TraceFile.FullName.EndsWith(lttngExtension)) { etlFileName = commandLineOptions.TraceFile.FullName.Substring(0, commandLineOptions.TraceFile.FullName.Length - lttngExtension.Length) + ".etlx"; PrintMessage($"Creating ETLX file {etlFileName} from {commandLineOptions.TraceFile.FullName}"); TraceLog.CreateFromLttngTextDataFile(commandLineOptions.TraceFile.FullName, etlFileName); } UnZipIfNecessary(ref etlFileName, commandLineOptions.BasicProgressMessages ? Console.Out : new StringWriter()); using (var traceLog = TraceLog.OpenOrConvert(etlFileName)) { if ((!commandLineOptions.Pid.HasValue && commandLineOptions.ProcessName == null) && traceLog.Processes.Count != 1) { PrintError("Trace file contains multiple processes to distinguish between"); PrintOutput("Either a pid or process name from the following list must be specified"); foreach (TraceProcess proc in traceLog.Processes) { PrintOutput($"Procname = {proc.Name} Pid = {proc.ProcessID}"); } return(1); } if (commandLineOptions.Pid.HasValue && (commandLineOptions.ProcessName != null)) { PrintError("--pid and --process-name cannot be specified together"); return(-1); } // For a particular process TraceProcess p; if (commandLineOptions.Pid.HasValue) { p = traceLog.Processes.LastProcessWithID(commandLineOptions.Pid.Value); } else if (commandLineOptions.ProcessName != null) { List <TraceProcess> matchingProcesses = new List <TraceProcess>(); foreach (TraceProcess proc in traceLog.Processes) { if (String.Compare(proc.Name, commandLineOptions.ProcessName, StringComparison.OrdinalIgnoreCase) == 0) { matchingProcesses.Add(proc); } } if (matchingProcesses.Count == 0) { PrintError("Unable to find matching process in trace"); return(-1); } if (matchingProcesses.Count > 1) { StringBuilder errorMessage = new StringBuilder(); errorMessage.AppendLine("Found multiple matching processes in trace"); foreach (TraceProcess proc in matchingProcesses) { errorMessage.AppendLine($"{proc.Name}\tpid={proc.ProcessID}\tCPUMSec={proc.CPUMSec}"); } PrintError(errorMessage.ToString()); return(-2); } p = matchingProcesses[0]; } else { p = traceLog.Processes.First(); } if (!p.EventsInProcess.ByEventType <MethodDetailsTraceData>().Any()) { PrintError($"No MethodDetails\nWas the trace collected with provider at least \"Microsoft-Windows-DotNETRuntime:0x4000080018:5\"?"); return(-3); } if (!p.EventsInProcess.ByEventType <GCBulkTypeTraceData>().Any()) { PrintError($"No BulkType data\nWas the trace collected with provider at least \"Microsoft-Windows-DotNETRuntime:0x4000080018:5\"?"); return(-4); } if (!p.EventsInProcess.ByEventType <ModuleLoadUnloadTraceData>().Any()) { PrintError($"No managed module load data\nWas the trace collected with provider at least \"Microsoft-Windows-DotNETRuntime:0x4000080018:5\"?"); return(-5); } if (!p.EventsInProcess.ByEventType <MethodJittingStartedTraceData>().Any()) { PrintError($"No managed jit starting data\nWas the trace collected with provider at least \"Microsoft-Windows-DotNETRuntime:0x4000080018:5\"?"); return(-5); } PgoTraceProcess pgoProcess = new PgoTraceProcess(p); int? clrInstanceId = commandLineOptions.ClrInstanceId; if (!clrInstanceId.HasValue) { HashSet <int> clrInstanceIds = new HashSet <int>(); HashSet <int> examinedClrInstanceIds = new HashSet <int>(); foreach (var assemblyLoadTrace in p.EventsInProcess.ByEventType <AssemblyLoadUnloadTraceData>()) { if (examinedClrInstanceIds.Add(assemblyLoadTrace.ClrInstanceID)) { if (pgoProcess.ClrInstanceIsCoreCLRInstance(assemblyLoadTrace.ClrInstanceID)) { clrInstanceIds.Add(assemblyLoadTrace.ClrInstanceID); } } } if (clrInstanceIds.Count != 1) { if (clrInstanceIds.Count == 0) { PrintError($"No managed CLR in target process, or per module information could not be loaded from the trace."); } else { // There are multiple clr processes... search for the one that implements int[] clrInstanceIdsArray = clrInstanceIds.ToArray(); Array.Sort(clrInstanceIdsArray); StringBuilder errorMessage = new StringBuilder(); errorMessage.AppendLine("Multiple CLR instances used in process. Choose one to examine with -clrInstanceID:<id> Valid ids:"); foreach (int instanceID in clrInstanceIds) { errorMessage.AppendLine(instanceID.ToString()); } PrintError(errorMessage.ToString()); } return(-10); } else { clrInstanceId = clrInstanceIds.First(); } } var tsc = new TraceTypeSystemContext(pgoProcess, clrInstanceId.Value, s_logger); if (commandLineOptions.VerboseWarnings) { PrintWarning($"{traceLog.EventsLost} Lost events"); } bool filePathError = false; if (commandLineOptions.Reference != null) { foreach (FileInfo fileReference in commandLineOptions.Reference) { if (!File.Exists(fileReference.FullName)) { PrintError($"Unable to find reference '{fileReference.FullName}'"); filePathError = true; } else { tsc.GetModuleFromPath(fileReference.FullName); } } } if (filePathError) { return(-6); } if (!tsc.Initialize()) { return(-12); } TraceRuntimeDescToTypeSystemDesc idParser = new TraceRuntimeDescToTypeSystemDesc(p, tsc, clrInstanceId.Value); SortedDictionary <int, ProcessedMethodData> methodsToAttemptToPrepare = new SortedDictionary <int, ProcessedMethodData>(); if (commandLineOptions.ProcessR2REvents) { foreach (var e in p.EventsInProcess.ByEventType <R2RGetEntryPointTraceData>()) { int parenIndex = e.MethodSignature.IndexOf('('); string retArg = e.MethodSignature.Substring(0, parenIndex); string paramsArgs = e.MethodSignature.Substring(parenIndex); string methodNameFromEventDirectly = retArg + e.MethodNamespace + "." + e.MethodName + paramsArgs; if (e.ClrInstanceID != clrInstanceId.Value) { if (!commandLineOptions.Warnings) { continue; } PrintWarning($"Skipped R2REntryPoint {methodNameFromEventDirectly} due to ClrInstanceID of {e.ClrInstanceID}"); continue; } MethodDesc method = null; string extraWarningText = null; try { method = idParser.ResolveMethodID(e.MethodID, commandLineOptions.VerboseWarnings); } catch (Exception exception) { extraWarningText = exception.ToString(); } if (method == null) { if ((e.MethodNamespace == "dynamicClass") || !commandLineOptions.Warnings) { continue; } PrintWarning($"Unable to parse {methodNameFromEventDirectly} when looking up R2R methods"); if (extraWarningText != null) { PrintWarning(extraWarningText); } continue; } if ((e.TimeStampRelativeMSec >= commandLineOptions.ExcludeEventsBefore) && (e.TimeStampRelativeMSec <= commandLineOptions.ExcludeEventsAfter)) { methodsToAttemptToPrepare.Add((int)e.EventIndex, new ProcessedMethodData(e.TimeStampRelativeMSec, method, "R2RLoad")); } } } // Find all the jitStart events. if (commandLineOptions.ProcessJitEvents) { foreach (var e in p.EventsInProcess.ByEventType <MethodJittingStartedTraceData>()) { int parenIndex = e.MethodSignature.IndexOf('('); string retArg = e.MethodSignature.Substring(0, parenIndex); string paramsArgs = e.MethodSignature.Substring(parenIndex); string methodNameFromEventDirectly = retArg + e.MethodNamespace + "." + e.MethodName + paramsArgs; if (e.ClrInstanceID != clrInstanceId.Value) { if (!commandLineOptions.Warnings) { continue; } PrintWarning($"Skipped {methodNameFromEventDirectly} due to ClrInstanceID of {e.ClrInstanceID}"); continue; } MethodDesc method = null; string extraWarningText = null; try { method = idParser.ResolveMethodID(e.MethodID, commandLineOptions.VerboseWarnings); } catch (Exception exception) { extraWarningText = exception.ToString(); } if (method == null) { if ((e.MethodNamespace == "dynamicClass") || !commandLineOptions.Warnings) { continue; } PrintWarning($"Unable to parse {methodNameFromEventDirectly}"); if (extraWarningText != null) { PrintWarning(extraWarningText); } continue; } if ((e.TimeStampRelativeMSec >= commandLineOptions.ExcludeEventsBefore) && (e.TimeStampRelativeMSec <= commandLineOptions.ExcludeEventsAfter)) { methodsToAttemptToPrepare.Add((int)e.EventIndex, new ProcessedMethodData(e.TimeStampRelativeMSec, method, "JitStart")); } } } Dictionary <MethodDesc, Dictionary <MethodDesc, int> > callGraph = null; Dictionary <MethodDesc, int> exclusiveSamples = null; if (commandLineOptions.GenerateCallGraph) { HashSet <MethodDesc> methodsListedToPrepare = new HashSet <MethodDesc>(); foreach (var entry in methodsToAttemptToPrepare) { methodsListedToPrepare.Add(entry.Value.Method); } callGraph = new Dictionary <MethodDesc, Dictionary <MethodDesc, int> >(); exclusiveSamples = new Dictionary <MethodDesc, int>(); // Capture the addresses of jitted code List <ValueTuple <InstructionPointerRange, MethodDesc> > codeLocations = new List <(InstructionPointerRange, MethodDesc)>(); foreach (var e in p.EventsInProcess.ByEventType <MethodLoadUnloadTraceData>()) { if (e.ClrInstanceID != clrInstanceId.Value) { continue; } MethodDesc method = null; try { method = idParser.ResolveMethodID(e.MethodID, commandLineOptions.VerboseWarnings); } catch (Exception) { } if (method != null) { codeLocations.Add((new InstructionPointerRange(e.MethodStartAddress, e.MethodSize), method)); } } foreach (var e in p.EventsInProcess.ByEventType <MethodLoadUnloadVerboseTraceData>()) { if (e.ClrInstanceID != clrInstanceId.Value) { continue; } MethodDesc method = null; try { method = idParser.ResolveMethodID(e.MethodID, commandLineOptions.VerboseWarnings); } catch (Exception) { } if (method != null) { codeLocations.Add((new InstructionPointerRange(e.MethodStartAddress, e.MethodSize), 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) { codeLocations.Add((new InstructionPointerRange(module.ImageBase + (ulong)runtimeFunction.StartAddress, runtimeFunction.Size), methodEntry.Key)); } } } catch { } } InstructionPointerRange[] instructionPointerRanges = new InstructionPointerRange[codeLocations.Count]; MethodDesc[] methods = new MethodDesc[codeLocations.Count]; for (int i = 0; i < codeLocations.Count; i++) { instructionPointerRanges[i] = codeLocations[i].Item1; methods[i] = codeLocations[i].Item2; } Array.Sort(instructionPointerRanges, methods); foreach (var e in p.EventsInProcess.ByEventType <SampledProfileTraceData>()) { var callstack = e.CallStack(); if (callstack == null) { continue; } ulong address1 = callstack.CodeAddress.Address; MethodDesc topOfStackMethod = LookupMethodByAddress(address1); MethodDesc nextMethod = null; if (callstack.Caller != null) { ulong address2 = callstack.Caller.CodeAddress.Address; nextMethod = LookupMethodByAddress(address2); } if (topOfStackMethod != null) { if (!methodsListedToPrepare.Contains(topOfStackMethod)) { methodsListedToPrepare.Add(topOfStackMethod); methodsToAttemptToPrepare.Add((int)e.EventIndex, new ProcessedMethodData(e.TimeStampRelativeMSec, topOfStackMethod, "SampleMethod")); } if (exclusiveSamples.TryGetValue(topOfStackMethod, out int count)) { exclusiveSamples[topOfStackMethod] = count + 1; } else { exclusiveSamples[topOfStackMethod] = 1; } } if (topOfStackMethod != null && nextMethod != null) { if (!methodsListedToPrepare.Contains(nextMethod)) { methodsListedToPrepare.Add(nextMethod); methodsToAttemptToPrepare.Add((int)e.EventIndex, new ProcessedMethodData(e.TimeStampRelativeMSec, nextMethod, "SampleMethodCaller")); } if (!callGraph.TryGetValue(nextMethod, out var innerDictionary)) { innerDictionary = new Dictionary <MethodDesc, int>(); callGraph[nextMethod] = innerDictionary; } if (innerDictionary.TryGetValue(topOfStackMethod, out int count)) { innerDictionary[topOfStackMethod] = count + 1; } else { innerDictionary[topOfStackMethod] = 1; } } } MethodDesc LookupMethodByAddress(ulong address) { int index = Array.BinarySearch(instructionPointerRanges, new InstructionPointerRange(address, 1)); if (index >= 0) { return(methods[index]); } else { index = ~index; if (index >= instructionPointerRanges.Length) { return(null); } if (instructionPointerRanges[index].StartAddress < address) { if (instructionPointerRanges[index].EndAddress > address) { return(methods[index]); } } if (index == 0) { return(null); } index--; if (instructionPointerRanges[index].StartAddress < address) { if (instructionPointerRanges[index].EndAddress > address) { return(methods[index]); } } return(null); } } } Dictionary <MethodDesc, MethodChunks> instrumentationDataByMethod = new Dictionary <MethodDesc, MethodChunks>(); foreach (var e in p.EventsInProcess.ByEventType <JitInstrumentationDataVerboseTraceData>()) { AddToInstrumentationData(e.ClrInstanceID, e.MethodID, e.MethodFlags, e.Data); } foreach (var e in p.EventsInProcess.ByEventType <JitInstrumentationDataTraceData>()) { AddToInstrumentationData(e.ClrInstanceID, e.MethodID, e.MethodFlags, e.Data); } // Local function used with the above two loops as the behavior is supposed to be identical void AddToInstrumentationData(int eventClrInstanceId, long methodID, int methodFlags, byte[] data) { if (eventClrInstanceId != clrInstanceId.Value) { return; } MethodDesc method = null; try { method = idParser.ResolveMethodID(methodID, commandLineOptions.VerboseWarnings); } catch (Exception) { } if (method != null) { if (!instrumentationDataByMethod.TryGetValue(method, out MethodChunks perMethodChunks)) { perMethodChunks = new MethodChunks(); instrumentationDataByMethod.Add(method, perMethodChunks); } const int FinalChunkFlag = unchecked ((int)0x80000000); int chunkIndex = methodFlags & ~FinalChunkFlag; if ((chunkIndex != (perMethodChunks.LastChunk + 1)) || perMethodChunks.Done) { instrumentationDataByMethod.Remove(method); return; } perMethodChunks.LastChunk = perMethodChunks.InstrumentationData.Count; perMethodChunks.InstrumentationData.Add(data); if ((methodFlags & FinalChunkFlag) == FinalChunkFlag) { perMethodChunks.Done = true; } } } if (commandLineOptions.DisplayProcessedEvents) { foreach (var entry in methodsToAttemptToPrepare) { MethodDesc method = entry.Value.Method; string reason = entry.Value.Reason; PrintOutput($"{entry.Value.Millisecond.ToString("F4")} {reason} {method}"); } } PrintMessage($"Done processing input file"); if (commandLineOptions.OutputFileName == null) { return(0); } // Deduplicate entries HashSet <MethodDesc> methodsInListAlready = new HashSet <MethodDesc>(); List <ProcessedMethodData> methodsUsedInProcess = new List <ProcessedMethodData>(); PgoDataLoader pgoDataLoader = new PgoDataLoader(idParser); foreach (var entry in methodsToAttemptToPrepare) { if (methodsInListAlready.Add(entry.Value.Method)) { var methodData = entry.Value; if (commandLineOptions.GenerateCallGraph) { exclusiveSamples.TryGetValue(methodData.Method, out methodData.ExclusiveWeight); callGraph.TryGetValue(methodData.Method, out methodData.WeightedCallData); } if (instrumentationDataByMethod.TryGetValue(methodData.Method, out MethodChunks chunks)) { int size = 0; foreach (byte[] arr in chunks.InstrumentationData) { size += arr.Length; } byte[] instrumentationData = new byte[size]; int offset = 0; foreach (byte[] arr in chunks.InstrumentationData) { arr.CopyTo(instrumentationData, offset); offset += arr.Length; } var intDecompressor = new PgoProcessor.PgoEncodedCompressedIntParser(instrumentationData, 0); methodData.InstrumentationData = PgoProcessor.ParsePgoData <TypeSystemEntityOrUnknown>(pgoDataLoader, intDecompressor, true).ToArray(); } methodsUsedInProcess.Add(methodData); } } if (commandLineOptions.FileType.Value == PgoFileType.jittrace) { GenerateJittraceFile(commandLineOptions.OutputFileName, methodsUsedInProcess, commandLineOptions.JitTraceOptions); } else if (commandLineOptions.FileType.Value == PgoFileType.mibc) { ILCompiler.MethodProfileData[] methodProfileData = new ILCompiler.MethodProfileData[methodsUsedInProcess.Count]; for (int i = 0; i < methodProfileData.Length; i++) { ProcessedMethodData processedData = methodsUsedInProcess[i]; methodProfileData[i] = new ILCompiler.MethodProfileData(processedData.Method, ILCompiler.MethodProfilingDataFlags.ReadMethodCode, processedData.ExclusiveWeight, processedData.WeightedCallData, 0xFFFFFFFF, processedData.InstrumentationData); } return(MibcEmitter.GenerateMibcFile(tsc, commandLineOptions.OutputFileName, methodProfileData, commandLineOptions.ValidateOutputFile, commandLineOptions.Uncompressed)); } } return(0); }