internal static IModule GetInstrumented(IMetadataHost host, IModule module, PdbReader/*?*/ pdbReader, INamespaceTypeDefinition logger) { var copier = new MetadataDeepCopier(host); var copy = copier.Copy(module); var loggerCopy = copier.Copy(logger); loggerCopy.ContainingUnitNamespace = copy.UnitNamespaceRoot; var logEdgeCount = TypeHelper.GetMethod(loggerCopy, host.NameTable.GetNameFor("LogEdgeCount"), host.PlatformType.SystemUInt32); new Instrumenter(host, pdbReader, logEdgeCount).Rewrite(copy); copy.AllTypes.Add(loggerCopy); return copy; }
internal static IModule GetInstrumented(IMetadataHost host, IModule module, PdbReader /*?*/ pdbReader, INamespaceTypeDefinition logger) { var copier = new MetadataDeepCopier(host); var copy = copier.Copy(module); var loggerCopy = copier.Copy(logger); loggerCopy.ContainingUnitNamespace = copy.UnitNamespaceRoot; var logEdgeCount = TypeHelper.GetMethod(loggerCopy, host.NameTable.GetNameFor("LogEdgeCount"), host.PlatformType.SystemUInt32); new Instrumenter(host, pdbReader, logEdgeCount).Rewrite(copy); copy.AllTypes.Add(loggerCopy); return(copy); }
public override void RewriteChildren(NamedTypeDefinition typeDefinition) { if (typeDefinition.Properties == null) { return; } var props = typeDefinition.Properties .Select(x => new { Property = x, Attributes = x.Attributes //.Select(y => (NamespaceTypeDefinition)y.Type) .Select(y => y.Type as NamespaceTypeDefinition) .Where(y => y != null && y.Name.Value == "PropertyChangedAttribute") }) .Where(x => x.Attributes.Any()); if (!props.Any()) { return; } foreach (var p in props.ToArray()) { if (p.Property.Setter == null) { throw new InvalidOperationException(); } var copier = new MetadataDeepCopier(host); var p2 = copier.Copy(p.Property); typeDefinition.Properties.Remove(p.Property); typeDefinition.Properties.Add(p2); var method = copier.Copy(p2.Setter.ResolvedMethod); _rewriter.PropertyName = p2.Name.Value; _rewriter.Type = method.ContainingTypeDefinition; method.Body = _rewriter.Rewrite(method.Body); method.ContainingTypeDefinition = typeDefinition; var m = typeDefinition.Methods.FirstOrDefault(x => x.Name == p2.Setter.ResolvedMethod.Name); typeDefinition.Methods.Remove(m); typeDefinition.Methods.Add(method); } }
public override void RewriteChildren(NamedTypeDefinition typeDefinition) { if (typeDefinition.Properties == null) { return; } var props = typeDefinition.Properties .Select(x => new { Property = x, Attributes = x.Attributes //.Select(y => (NamespaceTypeDefinition)y.Type) .Select(y => y.Type as NamespaceTypeDefinition) .Where(y => y != null && y.Name.Value == "PropertyChangedAttribute") }) .Where(x => x.Attributes.Any()); if (!props.Any()) { return; } foreach (var p in props.ToArray()) { if (p.Property.Setter == null) { throw new InvalidOperationException(); } var copier = new MetadataDeepCopier(host); var p2 = copier.Copy(p.Property); typeDefinition.Properties.Remove(p.Property); typeDefinition.Properties.Add(p2); var method = copier.Copy(p2.Setter.ResolvedMethod); _rewriter.PropertyName = p2.Name.Value; _rewriter.Type = method.ContainingTypeDefinition; method.Body = _rewriter.Rewrite(method.Body); method.ContainingTypeDefinition = typeDefinition; var m = typeDefinition.Methods.FirstOrDefault(x => x.Name == p2.Setter.ResolvedMethod.Name); typeDefinition.Methods.Remove(m); typeDefinition.Methods.Add(method); } }
static void Main(string[] args) { if (args == null || args.Length == 0) { Console.WriteLine("usage: PeToPe [path]fileName.ext"); return; } using (var host = new PeReader.DefaultHost()) { var module = host.LoadUnitFrom(args[0]) as IModule; if (module == null || module is Dummy) { Console.WriteLine(args[0]+" is not a PE file containing a CLR module or assembly."); return; } PdbReader/*?*/ pdbReader = null; string pdbFile = module.DebugInformationLocation; if (string.IsNullOrEmpty(pdbFile)) pdbFile = Path.ChangeExtension(module.Location, "pdb"); if (File.Exists(pdbFile)) { Stream pdbStream = File.OpenRead(pdbFile); pdbReader = new PdbReader(pdbStream, host); } using (pdbReader) { //Make a mutable copy of the module. var copier = new MetadataDeepCopier(host); var mutableModule = copier.Copy(module); //Traverse the module. In a real application the MetadataVisitor and/or the MetadataTravers will be subclasses //and the traversal will gather information to use during rewriting. var traverser = new MetadataTraverser() { PreorderVisitor = new MetadataVisitor(), TraverseIntoMethodBodies = true }; traverser.Traverse(mutableModule); //Rewrite the mutable copy. In a real application the rewriter would be a subclass of MetadataRewriter that actually does something. var rewriter = new MetadataRewriter(host); var rewrittenModule = rewriter.Rewrite(mutableModule); //Write out rewritten module. using (var peStream = File.Create(rewrittenModule.Location + ".pe")) { if (pdbReader == null) { PeWriter.WritePeToStream(rewrittenModule, host, peStream); } else { //Note that the default copier and rewriter preserves the locations collections, so the original pdbReader is still a valid ISourceLocationProvider. //However, if IL instructions were rewritten, the pdbReader will no longer be an accurate ILocalScopeProvider using (var pdbWriter = new PdbWriter(pdbFile + ".pdb", pdbReader)) { PeWriter.WritePeToStream(rewrittenModule, host, peStream, pdbReader, pdbReader, pdbWriter); } } } } } }
void RoundTripMutableCopyAndAddGenericParameter2(string assemblyName) { PeVerifyResult expectedResult = PeVerify.VerifyAssembly(assemblyName); IAssembly assembly = LoadAssembly(assemblyName); var copier1 = new MetadataDeepCopier(host); var codeAssembly = copier1.Copy(assembly); for (int i = 0; i < 30; i++) { AddGenericParameters adder = new AddGenericParameters(host, codeAssembly.AllTypes, i); codeAssembly = (Assembly)adder.Rewrite(codeAssembly); } AssertWriteToPeFile(expectedResult, codeAssembly, null); }
public static void Main(string[] args) { string seeds = null; string contracts = null; string facadePath = null; Version assemblyFileVersion = null; bool clearBuildAndRevision = false; bool ignoreMissingTypes = false; bool buildDesignTimeFacades = false; string inclusionContracts = null; ErrorTreatment seedLoadErrorTreatment = ErrorTreatment.Default; ErrorTreatment contractLoadErrorTreatment = ErrorTreatment.Default; string[] seedTypePreferencesUnsplit = null; bool forceZeroVersionSeeds = false; bool producePdb = true; string partialFacadeAssemblyPath = null; bool parsingSucceeded = CommandLineParser.ParseForConsoleApplication((parser) => { parser.DefineQualifier("facadePath", ref facadePath, "Path to output the facades."); parser.DefineQualifier("seeds", ref seeds, "Path to the seed assemblies. Can contain multiple assemblies or directories delimited by ',' or ';'."); parser.DefineQualifier("contracts", ref contracts, "Path to the contract assemblies. Can contain multiple assemblies or directories delimited by ',' or ';'."); parser.DefineOptionalQualifier("assemblyFileVersion", ref assemblyFileVersion, "Override the AssemblyFileVersion attribute from the contract with the given version for the generated facade."); parser.DefineOptionalQualifier("clearBuildAndRevision", ref clearBuildAndRevision, "Generate facade assembly version x.y.0.0 for contract version x.y.z.w"); parser.DefineOptionalQualifier("ignoreMissingTypes", ref ignoreMissingTypes, "Ignore types that cannot be found in the seed assemblies. This is not recommended but is sometimes helpful while hacking around or trying to produce partial facades."); parser.DefineOptionalQualifier("designTime", ref buildDesignTimeFacades, "Enable design-time facade generation (marks facades with reference assembly flag and attribute)."); parser.DefineOptionalQualifier("include", ref inclusionContracts, "Add types from these contracts to the facades. Can contain multiple assemblies or directories delimited by ',' or ';'."); parser.DefineOptionalQualifier("seedError", ref seedLoadErrorTreatment, "Error handling for seed assembly load failure."); parser.DefineOptionalQualifier("contractError", ref seedLoadErrorTreatment, "Error handling for contract assembly load failure."); parser.DefineOptionalQualifier("preferSeedType", ref seedTypePreferencesUnsplit, "Set which seed assembly to choose for a given type when it is defined in more than one assembly. Format: FullTypeName=PreferredSeedAssemblyName"); parser.DefineOptionalQualifier("forceZeroVersionSeeds", ref forceZeroVersionSeeds, "Forces all seed assembly versions to 0.0.0.0, regardless of their true version."); parser.DefineOptionalQualifier("partialFacadeAssemblyPath", ref partialFacadeAssemblyPath, "Specifies the path to a single partial facade assembly, into which appropriate type forwards will be added to satisfy the given contract. If this option is specified, only a single partial assembly and a single contract may be given."); parser.DefineOptionalQualifier("producePdb", ref producePdb, "Specifices if a PDB file should be produced for the resulting partial facade."); }, args); if (!parsingSucceeded) { return; } CommandLineTraceHandler.Enable(); if (!Directory.Exists(facadePath)) Directory.CreateDirectory(facadePath); var nameTable = new NameTable(); var internFactory = new InternFactory(); try { Dictionary<string, string> seedTypePreferences = ParseSeedTypePreferences(seedTypePreferencesUnsplit); using (var contractHost = new HostEnvironment(nameTable, internFactory)) using (var seedHost = new HostEnvironment(nameTable, internFactory)) { contractHost.LoadErrorTreatment = contractLoadErrorTreatment; seedHost.LoadErrorTreatment = seedLoadErrorTreatment; var contractAssemblies = LoadAssemblies(contractHost, contracts); IReadOnlyDictionary<string, IEnumerable<string>> docIdTable = GenerateDocIdTable(contractAssemblies, inclusionContracts); IAssembly[] seedAssemblies = LoadAssemblies(seedHost, seeds).ToArray(); IAssemblyReference seedCoreAssemblyRef = ((Microsoft.Cci.Immutable.PlatformType)seedHost.PlatformType).CoreAssemblyRef; if (forceZeroVersionSeeds) { // Create a deep copier, copy the seed assemblies, and zero out their versions. var copier = new MetadataDeepCopier(seedHost); for (int i = 0; i < seedAssemblies.Length; i++) { var mutableSeed = copier.Copy(seedAssemblies[i]); mutableSeed.Version = new Version(0, 0, 0, 0); // Copy the modified seed assembly back. seedAssemblies[i] = mutableSeed; if (mutableSeed.Name.UniqueKey == seedCoreAssemblyRef.Name.UniqueKey) { seedCoreAssemblyRef = mutableSeed; } } } var typeTable = GenerateTypeTable(seedAssemblies); var facadeGenerator = new FacadeGenerator(seedHost, contractHost, docIdTable, typeTable, seedTypePreferences, clearBuildAndRevision, buildDesignTimeFacades, assemblyFileVersion); if (partialFacadeAssemblyPath != null) { if (contractAssemblies.Count() != 1) { throw new FacadeGenerationException( "When partialFacadeAssemblyPath is specified, only exactly one corresponding contract assembly can be specified."); } IAssembly contractAssembly = contractAssemblies.First(); IAssembly partialFacadeAssembly = seedHost.LoadAssembly(partialFacadeAssemblyPath); if (contractAssembly.Name != partialFacadeAssembly.Name || contractAssembly.Version != partialFacadeAssembly.Version || contractAssembly.GetPublicKeyToken() != partialFacadeAssembly.GetPublicKeyToken()) { throw new FacadeGenerationException( string.Format("The partial facade assembly's name, version, and public key token must exactly match the contract to be filled. Contract: {0}, Facade: {1}", contractAssembly.AssemblyIdentity, partialFacadeAssembly.AssemblyIdentity)); } Assembly filledPartialFacade = facadeGenerator.GenerateFacade(contractAssembly, seedCoreAssemblyRef, ignoreMissingTypes, overrideContractAssembly: partialFacadeAssembly); string pdbLocation = null; if (producePdb) { string pdbFolder = Path.GetDirectoryName(partialFacadeAssemblyPath); pdbLocation = Path.Combine(pdbFolder, contractAssembly.Name + ".pdb"); if (producePdb && !File.Exists(pdbLocation)) { pdbLocation = null; Trace.TraceWarning("No PDB file present for un-transformed partial facade. No PDB will be generated."); } } OutputFacadeToFile(facadePath, seedHost, filledPartialFacade, contractAssembly, pdbLocation); } else { foreach (var contract in contractAssemblies) { Assembly facade = facadeGenerator.GenerateFacade(contract, seedCoreAssemblyRef, ignoreMissingTypes); if (facade == null) { #if !COREFX Debug.Assert(Environment.ExitCode != 0); #endif continue; } OutputFacadeToFile(facadePath, seedHost, facade, contract); } } } } catch (FacadeGenerationException ex) { Trace.TraceError(ex.Message); #if !COREFX Debug.Assert(Environment.ExitCode != 0); #endif } }
public Assembly GenerateFacade(IAssembly contractAssembly, IAssemblyReference seedCoreAssemblyReference, bool ignoreMissingTypes, IAssembly overrideContractAssembly = null, bool buildPartialReferenceFacade = false) { Assembly assembly; if (overrideContractAssembly != null) { MetadataDeepCopier copier = new MetadataDeepCopier(_seedHost); assembly = copier.Copy(overrideContractAssembly); // Use non-empty partial facade if present } else { MetadataDeepCopier copier = new MetadataDeepCopier(_contractHost); assembly = copier.Copy(contractAssembly); // if building a reference facade don't strip the contract if (!buildPartialReferenceFacade) { ReferenceAssemblyToFacadeRewriter rewriter = new ReferenceAssemblyToFacadeRewriter(_seedHost, _contractHost, seedCoreAssemblyReference, _assemblyFileVersion != null); rewriter.Rewrite(assembly); } } string contractAssemblyName = contractAssembly.AssemblyIdentity.Name.Value; IEnumerable <string> docIds = _docIdTable[contractAssemblyName]; // Add all the type forwards bool error = false; Dictionary <string, INamedTypeDefinition> existingDocIds = assembly.AllTypes.ToDictionary(typeDef => typeDef.RefDocId(), typeDef => typeDef); IEnumerable <string> docIdsToForward = buildPartialReferenceFacade ? existingDocIds.Keys : docIds.Where(id => !existingDocIds.ContainsKey(id)); Dictionary <string, INamedTypeReference> forwardedTypes = new Dictionary <string, INamedTypeReference>(); foreach (string docId in docIdsToForward) { IReadOnlyList <INamedTypeDefinition> seedTypes; if (!_typeTable.TryGetValue(docId, out seedTypes)) { if (!ignoreMissingTypes && !buildPartialReferenceFacade) { Trace.TraceError("Did not find type '{0}' in any of the seed assemblies.", docId); error = true; } continue; } INamedTypeDefinition seedType = GetSeedType(docId, seedTypes); if (seedType == null) { TraceDuplicateSeedTypeError(docId, seedTypes); error = true; continue; } if (buildPartialReferenceFacade) { // honor preferSeedType for keeping contract type string preferredSeedAssembly; bool keepType = _seedTypePreferences.TryGetValue(docId, out preferredSeedAssembly) && contractAssemblyName.Equals(preferredSeedAssembly, StringComparison.OrdinalIgnoreCase); if (keepType) { continue; } assembly.AllTypes.Remove(existingDocIds[docId]); forwardedTypes.Add(docId, seedType); } AddTypeForward(assembly, seedType); } if (buildPartialReferenceFacade) { if (forwardedTypes.Count == 0) { Trace.TraceError("Did not find any types in any of the seed assemblies."); return(null); } else { // for any thing that's now a typeforward, make sure typerefs point to that rather than // the type previously inside the assembly. TypeReferenceRewriter typeRefRewriter = new TypeReferenceRewriter(_seedHost, oldType => { INamedTypeReference newType = null; return(forwardedTypes.TryGetValue(oldType.DocId(), out newType) ? newType : oldType); }); typeRefRewriter.Rewrite(assembly); } } if (error) { return(null); } if (_assemblyFileVersion != null) { assembly.AssemblyAttributes.Add(CreateAttribute("System.Reflection.AssemblyFileVersionAttribute", seedCoreAssemblyReference.ResolvedAssembly, _assemblyFileVersion.ToString())); assembly.AssemblyAttributes.Add(CreateAttribute("System.Reflection.AssemblyInformationalVersionAttribute", seedCoreAssemblyReference.ResolvedAssembly, _assemblyFileVersion.ToString())); } if (_buildDesignTimeFacades) { assembly.AssemblyAttributes.Add(CreateAttribute("System.Runtime.CompilerServices.ReferenceAssemblyAttribute", seedCoreAssemblyReference.ResolvedAssembly)); assembly.Flags |= ReferenceAssemblyFlag; } if (_clearBuildAndRevision) { assembly.Version = new Version(assembly.Version.Major, assembly.Version.Minor, 0, 0); } AddWin32VersionResource(contractAssembly.Location, assembly); return(assembly); }
private Task LoadManagedData() { return _loadingManagedData ?? (_loadingManagedData = _tasks.Start(() => { if (_loadOptions.HasFlag(BinaryLoadOptions.NoManaged)) { return; } // load managed data from working file if (!IsManaged) { ILOnly.Value = false; return; } // copy this to a temporary file, because it locks the file until we're *really* done. try { var module = _host.LoadUnitFrom(WorkingCopy) as IModule; if (module == null || module is Dummy) { throw new CoAppException("{0} is not a PE file containing a CLR module or assembly.".format(Filename)); } ILOnly.Value = module.ILOnly; //Make a mutable copy of the module. var copier = new MetadataDeepCopier(_host); var mutableModule = copier.Copy(module); //Traverse the module. In a real application the MetadataVisitor and/or the MetadataTravers will be subclasses //and the traversal will gather information to use during rewriting. var traverser = new MetadataTraverser { PreorderVisitor = new MetadataVisitor(), TraverseIntoMethodBodies = true }; traverser.Traverse(mutableModule); //Rewrite the mutable copy. In a real application the rewriter would be a subclass of MetadataRewriter that actually does something. var rewriter = new MetadataRewriter(_host); _mutableAssembly = rewriter.Rewrite(mutableModule) as Assembly; AssemblyCulture.Value = _mutableAssembly.Culture; AssemblyVersion.Value = _mutableAssembly.Version; } finally { // delete it, or at least trash it & queue it up for next reboot. // temporaryCopy.TryHardToDelete(); } try { if (_mutableAssembly != null) { // we should see if we can get assembly attributes, since sometimes they can be set, but not the native ones. foreach (var a in _mutableAssembly.ContainingAssembly.AssemblyAttributes) { var attributeArgument = (a.Arguments.FirstOrDefault() as MetadataConstant); if (attributeArgument != null) { var attributeValue = attributeArgument.Value.ToString(); if (!string.IsNullOrEmpty(attributeValue)) { switch (a.Type.ToString()) { case "System.Reflection.AssemblyTitleAttribute": _fileDescription = _fileDescription ?? attributeValue; break; case "System.Reflection.AssemblyCompanyAttribute": _companyName = _companyName ?? attributeValue; break; case "System.Reflection.AssemblyProductAttribute": _productName = _productName ?? attributeValue; break; // case "System.Reflection.AssemblyVersionAttribute": // _assemblyVersion = _assemblyVersion == 0L ? (FourPartVersion)attributeValue : _assemblyVersion; // break; case "System.Reflection.AssemblyFileVersionAttribute": _fileVersion = _fileVersion == 0L ? (FourPartVersion)attributeValue : _fileVersion; _productVersion = _productVersion == 0L ? (FourPartVersion)attributeValue : _productVersion; break; case "System.Reflection.AssemblyCopyrightAttribute": _legalCopyright = _legalCopyright ?? attributeValue; break; case "System.Reflection.AssemblyTrademarkAttribute": _legalTrademarks = _legalTrademarks ?? attributeValue; break; case "System.Reflection.AssemblyDescriptionAttribute": _comments = _comments ?? attributeValue; break; case "BugTrackerAttribute": _bugTracker = _bugTracker ?? attributeValue; break; } } } } } } catch (Exception e) { Console.WriteLine("{0} -- {1}", e.Message, e.StackTrace); } // if there are dependencies, this will load them. if (_loadOptions.HasFlag(BinaryLoadOptions.UnsignedManagedDependencies)) { LoadUnsignedManagedDependencies(); } })); }
static void Main(string[] args) { if (args == null || args.Length == 0) { Console.WriteLine("usage: PeToPe [path]fileName.ext"); return; } using (var host = new PeReader.DefaultHost()) { var module = host.LoadUnitFrom(args[0]) as IModule; if (module == null || module is Dummy) { Console.WriteLine(args[0] + " is not a PE file containing a CLR module or assembly."); return; } PdbReader /*?*/ pdbReader = null; string pdbFile = module.DebugInformationLocation; if (string.IsNullOrEmpty(pdbFile)) { pdbFile = Path.ChangeExtension(module.Location, "pdb"); } if (File.Exists(pdbFile)) { Stream pdbStream = File.OpenRead(pdbFile); pdbReader = new PdbReader(pdbStream, host); } using (pdbReader) { //Make a mutable copy of the module. var copier = new MetadataDeepCopier(host); var mutableModule = copier.Copy(module); //Traverse the module. In a real application the MetadataVisitor and/or the MetadataTravers will be subclasses //and the traversal will gather information to use during rewriting. var traverser = new MetadataTraverser() { PreorderVisitor = new MetadataVisitor(), TraverseIntoMethodBodies = true }; traverser.Traverse(mutableModule); //Rewrite the mutable copy. In a real application the rewriter would be a subclass of MetadataRewriter that actually does something. var rewriter = new MetadataRewriter(host); var rewrittenModule = rewriter.Rewrite(mutableModule); //Write out rewritten module. using (var peStream = File.Create(rewrittenModule.Location + ".pe")) { if (pdbReader == null) { PeWriter.WritePeToStream(rewrittenModule, host, peStream); } else { //Note that the default copier and rewriter preserves the locations collections, so the original pdbReader is still a valid ISourceLocationProvider. //However, if IL instructions were rewritten, the pdbReader will no longer be an accurate ILocalScopeProvider using (var pdbWriter = new PdbWriter(pdbFile + ".pdb", pdbReader)) { PeWriter.WritePeToStream(rewrittenModule, host, peStream, pdbReader, pdbReader, pdbWriter); } } } } } }
/// <summary> /// Gets a mutable copy of the target assembly. /// </summary> /// <param name="target"> /// The assembly to retrieve the mutable copy for. /// </param> /// <param name="host"> /// The host to use when loading the assembly. /// </param> /// <returns> /// A mutable copy of the target assembly. /// </returns> private static Assembly GetMutableAssembly(IAssemblyTarget target, IMetadataHost host) { var copier = new MetadataDeepCopier(host); return copier.Copy(LoadModule(target, host)); }
public static Assembly PruneAssembly(HostEnvironment host, ISlice <MethodReferenceAdaptor, FieldReferenceAdaptor, TypeReferenceAdaptor, IAssemblyReference> slice) { Contract.Requires(host != null); Contract.Requires(slice != null); var newAssemblyName = slice.Name; var originalAssembly = slice.ContainingAssembly.ResolvedAssembly; Contract.Assume(!(originalAssembly is Dummy)); var methodDefsToKeep = new HashSet <uint>(); foreach (var m in slice.Methods) { methodDefsToKeep.Add(m.reference.InternedKey); } var copier = new MetadataDeepCopier(host); var thingsToKeep = new HashSet <object>(); var methodHashAttributes = new Dictionary <IMethodDefinition, MethodHashAttribute>(); var me = new Prune(host, copier, thingsToKeep, methodDefsToKeep, methodHashAttributes); // 1. everything that is specified in the slice should definitely be kept. foreach (var c in slice.Chains) { me.VisitChain(c); } // 2. everything reachable from the initial set of things to keep should be kept Dictionary <IMethodDefinition, uint> contractOffsets; FindReachable.Reachable(host, slice, thingsToKeep, methodDefsToKeep, out contractOffsets); me.contractOffsets = contractOffsets; // 3. copy the original assembly --- entirely! var a_prime = copier.Copy(originalAssembly); var nameTable = host.NameTable; a_prime.ModuleName = nameTable.GetNameFor(newAssemblyName + ".dll"); a_prime.Name = nameTable.GetNameFor(newAssemblyName); var mutableRoot = (RootUnitNamespace)(a_prime.UnitNamespaceRoot); var methodHashAttributeType = DefineMethodHashAttributeType(host, mutableRoot); me.methodHashAttributeCtor = new Microsoft.Cci.MethodReference( host, methodHashAttributeType, CallingConvention.HasThis, host.PlatformType.SystemVoid, host.NameTable.Ctor, 0, me.systemString, me.systemInt); // 4. delete all unwanted things from the mutable copy me.RewriteChildren(a_prime); var remainingTypes = new List <INamedTypeDefinition>(a_prime.AllTypes.Count); // will only shrink remainingTypes.Add(a_prime.AllTypes[0]); // <Module> class is always kept for (int i = 1, n = a_prime.AllTypes.Count; i < n; i++) { var t = a_prime.AllTypes[i]; Contract.Assume(t != null); Contract.Assume(copier.OriginalFor.ContainsKey(t)); var orig = copier.OriginalFor[t]; if (thingsToKeep.Contains(orig)) { remainingTypes.Add(t); } } a_prime.AllTypes = remainingTypes; // do this afterwards so it doesn't get visited. mutableRoot.Members.Add(methodHashAttributeType); a_prime.AllTypes.Add(methodHashAttributeType); return(a_prime); }
public static void RunBclRewriter(string[] args) { #region Parse the command-line arguments. if (!Parser.ParseArgumentsWithUsage(args, typeof(Program))) { throw new UsageException(); } #endregion #region Figure out paths s_assemblyName = Path.GetFullPath(s_assemblyName); // this has to be specified string outputBaseName = null; if (!String.IsNullOrEmpty(s_output)) { s_output = Path.GetFullPath(s_output); outputBaseName = Path.GetFileNameWithoutExtension(s_output); } else { s_output = Path.Combine(Directory.GetCurrentDirectory(), Path.GetFileNameWithoutExtension(s_assemblyName) + ".small" + Path.GetExtension(s_assemblyName)); outputBaseName = s_assemblyName; } string pdbSourceFile = Path.ChangeExtension(s_assemblyName, "pdb"); string outputPdb = Path.ChangeExtension(s_output, "pdb"); string outputFolder = Path.GetDirectoryName(s_output); // if the user wants to do an in-place rewrite, we copy the file to a temp file if (s_output == s_assemblyName) { String tempPath = s_assemblyName + TempExtension; String tempPdbPath = pdbSourceFile + TempExtension; File.Copy(s_assemblyName, tempPath, true); s_assemblyName = tempPath; if (File.Exists(pdbSourceFile)) { File.Copy(pdbSourceFile, tempPdbPath, true); pdbSourceFile = tempPdbPath; } } if (!Directory.Exists(outputFolder)) { Directory.CreateDirectory(outputFolder); } #endregion #region Load input files HostEnvironment host = new HostEnvironment(new NameTable(), s_assemblyDependencyPaths, s_referencedAssemblies); IAssembly /*?*/ assembly = host.LoadUnitFrom(s_assemblyName) as IAssembly; // TODO: Handle multimodule assemblies if (assembly == null || assembly == Dummy.Assembly) { throw new UsageException(args[0] + " is not a PE file containing a CLR assembly, or an error occurred when loading it."); } if (!File.Exists(s_includeListFile)) { throw new UsageException(String.Format("ERROR: Can't find code model file '{0}'", s_includeListFile)); } ThinModel model = new ThinModel(new ThinnerOptions(host, new AssemblyIdentity[] { assembly.AssemblyIdentity })); model.LoadModel(s_includeListFile, new ModelReaderOptions(s_platform, s_architecture, s_flavor, s_treatFxInternalAsPublic, s_defines)); #endregion #region Calculate api closure. ConsoleTimer.StartTimer("Calculating api closure"); model.LoadMetadataFrom(assembly); ThinModel apiClosure = model.CalculateApiClosure(); if (s_keepTempFiles) { apiClosure.SaveModel(Path.ChangeExtension(s_output, ".apiClosure.xml")); } ConsoleTimer.EndTimer("Calculating api closure"); #endregion #region Calculate impl closure. ConsoleTimer.StartTimer("Calculating implementation closure"); apiClosure.LoadMetadataFrom(assembly); ThinModel implClosure = apiClosure.CalculateImplementationClosure(true, FieldOptions.KeepAll); if (s_keepTempFiles) { implClosure.SaveModel(Path.ChangeExtension(s_output, ".implClosure.xml")); } ConsoleTimer.EndTimer("Calculating implementation closure"); #endregion #region Trim. ConsoleTimer.StartTimer("Trimming assembly"); IncludeSet includeSet = new IncludeSet(); includeSet.LoadFrom(implClosure); var copier = new MetadataDeepCopier(host); Assembly copiedAssembly = copier.Copy(assembly); Trimmer trimmer = new Trimmer(includeSet, true, false, true, host, s_removeSerializable); trimmer.RewriteChildren(copiedAssembly); Assembly mutableAssembly = copiedAssembly; assembly = mutableAssembly; ConsoleTimer.EndTimer("Trimming assembly"); #endregion #region Update assembly name. ConsoleTimer.StartTimer("Updating assembly name"); // If the output assembly name is different, update the internal assembly name to match. AssemblyIdentity originalAssemblyIdentity = mutableAssembly.AssemblyIdentity; if (!outputBaseName.Equals(originalAssemblyIdentity.Name.ToString(), StringComparison.OrdinalIgnoreCase)) { mutableAssembly.Name = host.NameTable.GetNameFor(outputBaseName); mutableAssembly.ModuleName = mutableAssembly.Name; } // If we changed the assembly identity, update references to it. if (!mutableAssembly.AssemblyIdentity.Equals(originalAssemblyIdentity)) { trimmer.UpdateAssemblyReferences(originalAssemblyIdentity, mutableAssembly.AssemblyIdentity); } ConsoleTimer.EndTimer("Updating assembly name"); #endregion #region Write out the assembly ConsoleTimer.StartTimer("Writing assembly"); PdbReader pdbReader = null; PdbWriter pdbWriter = null; if (File.Exists(pdbSourceFile)) { Stream pdbStream = File.OpenRead(pdbSourceFile); pdbReader = new PdbReader(pdbStream, host); pdbWriter = new PdbWriter(outputPdb, pdbReader); Console.WriteLine("Writing pdb: {0}", outputPdb); } Console.WriteLine("Writing assembly: {0}", s_output); FileStream file = File.Create(s_output); try { PeWriter.WritePeToStream(assembly, host, file, pdbReader, pdbReader, pdbWriter); } finally { if (file != null) { file.Dispose(); } if (pdbWriter != null) { pdbWriter.Dispose(); } } ConsoleTimer.EndTimer("Writing assembly"); #endregion }
static int RealMain(string[] args) { int errorReturnValue = -1; #region Check options ILMerge.options = new ILMergeOptions(); options.Parse(args); if (options.HelpRequested) { options.PrintOptions(""); return(errorReturnValue); } if (options.HasErrors) { options.PrintErrorsAndExit(Console.Out); } if (options.breakIntoDebugger) { System.Diagnostics.Debugger.Break(); } #endregion Version version = null; if (options.version != null) { TryGetVersionNumber(options.version, out version); } using (var host = new ILMergeHost(options.libpaths)) { if (options.libpaths != null) { foreach (var libpath in options.libpaths) { host.AddLibPath(libpath); } } Assembly /*?*/ primaryAssembly = null; var modules = new List <Module>(); var unit2SourceLocationProviderMap = new Dictionary <IUnit, ISourceLocationProvider>(); var unit2LocalScopeProviderMap = new Dictionary <IUnit, ILocalScopeProvider>(); try { for (int i = 0; i < options.GeneralArguments.Count; i++) { var unitName = options.GeneralArguments[i]; var u = host.LoadUnitFrom(unitName) as IModule; if (i == 0) { IAssembly /*?*/ assembly = u as IAssembly; if (assembly == null || assembly is Dummy) { Console.WriteLine(unitName + " is not a PE file containing a CLR assembly, or an error occurred when loading it."); return(errorReturnValue); } // Use (the copy of) the first input assembly as the merged assembly! primaryAssembly = new MetadataDeepCopier(host).Copy(assembly); } else { var copier = new MetadataDeepCopier(host, primaryAssembly); var mutableModule = copier.Copy(u); modules.Add(mutableModule); } PdbReader /*?*/ pdbReader = null; string pdbFile = Path.ChangeExtension(u.Location, "pdb"); if (File.Exists(pdbFile)) { using (var pdbStream = File.OpenRead(pdbFile)) { pdbReader = new PdbReader(pdbStream, host); } unit2SourceLocationProviderMap.Add(u, pdbReader); unit2LocalScopeProviderMap.Add(u, pdbReader); } else { Console.WriteLine("Could not load the PDB file for the unit '" + u.Name.Value + "' . Proceeding anyway."); unit2SourceLocationProviderMap.Add(u, null); } } //PdbWriter/*?*/ pdbWriter = null; RewriteUnitReferences renamer = new RewriteUnitReferences(host, modules, options); renamer.targetAssembly = primaryAssembly; renamer.originalAssemblyIdentity = primaryAssembly.AssemblyIdentity; int totalNumberOfTypes = primaryAssembly.AllTypes.Count; #region Pass 1: Mutate each input module (including the primary assembly) so everything is re-parented to the merged assembly renamer.RewriteChildren(primaryAssembly); for (int i = 0, n = modules.Count; i < n; i++) { var mutableModule = modules[i]; // call Rewrite and not RewriteChildren so dynamic dispatch can call the right rewriter method // otherwise, it just rewrites it as a module, not whatever subtype it is. renamer.Rewrite(mutableModule); // However, the rewriter does *not* rewrite parents. So need to re-parent the root unit namespace // of the mutable assembly so it points to the merged assembly. Otherwise, interning (among other // things) will not work correctly. var rootUnitNs = (RootUnitNamespace)mutableModule.UnitNamespaceRoot; rootUnitNs.Unit = primaryAssembly; totalNumberOfTypes += mutableModule.AllTypes.Count; } #endregion #region Pass 2: Collect all of the types into the merged assembly var mergedTypes = new List <INamedTypeDefinition>(totalNumberOfTypes); #region Merge together all of the <Module> classes from the input assemblies // TODO: Merge all of the <Module> classes, i.e., type 0 from each of the input assemblies mergedTypes.Add(primaryAssembly.AllTypes[0]); #endregion var internedKeys = new HashSet <string>(); // keep track of all namespace type definitions #region Types from the primary assembly for (int i = 1, n = primaryAssembly.AllTypes.Count; i < n; i++) { var t = primaryAssembly.AllTypes[i]; mergedTypes.Add(t); if (t is INamespaceTypeDefinition) // don't care about nested types { var key = TypeHelper.GetTypeName(t, NameFormattingOptions.None); internedKeys.Add(key); } } #endregion #region Types from the other input assemblies, taking care of duplicates for (int i = 0, n = modules.Count; i < n; i++) { var module = modules[i]; var unitName = module.Name.Value; for (int j = 1, m = module.AllTypes.Count; j < m; j++) { var t = module.AllTypes[j]; var namespaceTypeDefinition = t as NamespaceTypeDefinition; // duplicates can be only at the top-level: namespace type definitions // if a namespace type definition is unique, then so are all of its nested types if (namespaceTypeDefinition != null) { var typeName = TypeHelper.GetTypeName(namespaceTypeDefinition, NameFormattingOptions.UseGenericTypeNameSuffix); if (internedKeys.Contains(typeName)) // error: duplicate! { if (!namespaceTypeDefinition.IsPublic || options.allowDup) { var newName = String.Format("{0}_from_{1}", namespaceTypeDefinition.Name.Value, unitName); namespaceTypeDefinition.Name = host.NameTable.GetNameFor(newName); var newTypeName = TypeHelper.GetTypeName(namespaceTypeDefinition, NameFormattingOptions.UseGenericTypeNameSuffix); Console.WriteLine("Adding '{0}' as '{1}'", typeName, newTypeName); internedKeys.Add(typeName); t = namespaceTypeDefinition; } else { Console.WriteLine("Error: Duplicate type '{0}'", typeName); continue; //TODO: set a flag somewhere to force a failure. } } else { //Console.WriteLine("Adding '{0}'", typeName); internedKeys.Add(typeName); } } mergedTypes.Add(t); } } #endregion primaryAssembly.AllTypes = mergedTypes; #endregion CopyResourcesToPrimaryAssembly(primaryAssembly, modules); if (version != null) { primaryAssembly.Version = version; } string outputPath; if (options.output != null) { outputPath = options.output; } else { outputPath = primaryAssembly.Name.Value + Path.GetExtension(options.GeneralArguments[0]) + ".meta"; } using (var aggregateSourceLocationProvider = new AggregatingSourceLocationProvider(unit2SourceLocationProviderMap)) { using (var aggregateLocalScopeProvider = new AggregatingLocalScopeProvider(unit2LocalScopeProviderMap)) { using (var peStream = File.Create(outputPath)) { using (var pdbWriter = new PdbWriter(Path.ChangeExtension(outputPath, "pdb"), aggregateSourceLocationProvider)) { PeWriter.WritePeToStream(primaryAssembly, host, peStream, aggregateSourceLocationProvider, aggregateLocalScopeProvider, pdbWriter); } } } } } finally { } return(0); // success } }
public static Assembly PruneAssembly(HostEnvironment host, ISlice<MethodReferenceAdaptor, FieldReferenceAdaptor, TypeReferenceAdaptor, IAssemblyReference> slice) { Contract.Requires(host != null); Contract.Requires(slice != null); var newAssemblyName = slice.Name; var originalAssembly = slice.ContainingAssembly.ResolvedAssembly; Contract.Assume(!(originalAssembly is Dummy)); var methodDefsToKeep = new HashSet<uint>(); foreach (var m in slice.Methods) { methodDefsToKeep.Add(m.reference.InternedKey); } var copier = new MetadataDeepCopier(host); var thingsToKeep = new HashSet<object>(); var methodHashAttributes = new Dictionary<IMethodDefinition, MethodHashAttribute>(); var me = new Prune(host, copier, thingsToKeep, methodDefsToKeep, methodHashAttributes); // 1. everything that is specified in the slice should definitely be kept. foreach (var c in slice.Chains) { me.VisitChain(c); } // 2. everything reachable from the initial set of things to keep should be kept Dictionary<IMethodDefinition, uint> contractOffsets; FindReachable.Reachable(host, slice, thingsToKeep, methodDefsToKeep, out contractOffsets); me.contractOffsets = contractOffsets; // 3. copy the original assembly --- entirely! var a_prime = copier.Copy(originalAssembly); var nameTable = host.NameTable; a_prime.ModuleName = nameTable.GetNameFor(newAssemblyName + ".dll"); a_prime.Name = nameTable.GetNameFor(newAssemblyName); var mutableRoot = (RootUnitNamespace)(a_prime.UnitNamespaceRoot); var methodHashAttributeType = DefineMethodHashAttributeType(host, mutableRoot); me.methodHashAttributeCtor = new Microsoft.Cci.MethodReference( host, methodHashAttributeType, CallingConvention.HasThis, host.PlatformType.SystemVoid, host.NameTable.Ctor, 0, me.systemString, me.systemInt); // 4. delete all unwanted things from the mutable copy me.RewriteChildren(a_prime); var remainingTypes = new List<INamedTypeDefinition>(a_prime.AllTypes.Count); // will only shrink remainingTypes.Add(a_prime.AllTypes[0]); // <Module> class is always kept for (int i = 1, n = a_prime.AllTypes.Count; i < n; i++) { var t = a_prime.AllTypes[i]; Contract.Assume(t!= null); Contract.Assume(copier.OriginalFor.ContainsKey(t)); var orig = copier.OriginalFor[t]; if (thingsToKeep.Contains(orig)) remainingTypes.Add(t); } a_prime.AllTypes = remainingTypes; // do this afterwards so it doesn't get visited. mutableRoot.Members.Add(methodHashAttributeType); a_prime.AllTypes.Add(methodHashAttributeType); return a_prime; }
public Assembly GenerateFacade(IAssembly contractAssembly, IAssemblyReference seedCoreAssemblyReference, bool ignoreMissingTypes, IAssembly overrideContractAssembly = null) { Assembly assembly; if (overrideContractAssembly != null) { MetadataDeepCopier copier = new MetadataDeepCopier(_seedHost); assembly = copier.Copy(overrideContractAssembly); // Use non-empty partial facade if present } else { MetadataDeepCopier copier = new MetadataDeepCopier(_contractHost); assembly = copier.Copy(contractAssembly); ReferenceAssemblyToFacadeRewriter rewriter = new ReferenceAssemblyToFacadeRewriter(_seedHost, _contractHost, seedCoreAssemblyReference, _assemblyFileVersion != null); rewriter.Rewrite(assembly); } IEnumerable<string> docIds = _docIdTable[contractAssembly.AssemblyIdentity.Name.Value]; // Add all the type forwards bool error = false; HashSet<string> existingDocIds = new HashSet<string>(assembly.AllTypes.Select(typeDef => typeDef.RefDocId())); IEnumerable<string> missingDocIds = docIds.Where(id => !existingDocIds.Contains(id)); foreach (string docId in missingDocIds) { IReadOnlyList<INamedTypeDefinition> seedTypes; if (!_typeTable.TryGetValue(docId, out seedTypes)) { if (!ignoreMissingTypes) { Trace.TraceError("Did not find type '{0}' in any of the seed assemblies.", docId); error = true; } continue; } INamedTypeDefinition seedType = GetSeedType(docId, seedTypes); if (seedType == null) { TraceDuplicateSeedTypeError(docId, seedTypes); error = true; continue; } AddTypeForward(assembly, seedType); } if (error) { return null; } if (_assemblyFileVersion != null) { assembly.AssemblyAttributes.Add(CreateAttribute("System.Reflection.AssemblyFileVersionAttribute", seedCoreAssemblyReference.ResolvedAssembly, _assemblyFileVersion.ToString())); assembly.AssemblyAttributes.Add(CreateAttribute("System.Reflection.AssemblyInformationalVersionAttribute", seedCoreAssemblyReference.ResolvedAssembly, _assemblyFileVersion.ToString())); } if (_buildDesignTimeFacades) { assembly.AssemblyAttributes.Add(CreateAttribute("System.Runtime.CompilerServices.ReferenceAssemblyAttribute", seedCoreAssemblyReference.ResolvedAssembly)); assembly.Flags |= ReferenceAssemblyFlag; } if (_clearBuildAndRevision) { assembly.Version = new Version(assembly.Version.Major, assembly.Version.Minor, 0, 0); } AddWin32VersionResource(contractAssembly.Location, assembly); return assembly; }
public static bool Execute( string seeds, string contracts, string facadePath, Version assemblyFileVersion = null, bool clearBuildAndRevision = false, bool ignoreMissingTypes = false, bool ignoreBuildAndRevisionMismatch = false, bool buildDesignTimeFacades = false, string inclusionContracts = null, ErrorTreatment seedLoadErrorTreatment = ErrorTreatment.Default, ErrorTreatment contractLoadErrorTreatment = ErrorTreatment.Default, string[] seedTypePreferencesUnsplit = null, bool forceZeroVersionSeeds = false, bool producePdb = true, string partialFacadeAssemblyPath = null) { if (!Directory.Exists(facadePath)) { Directory.CreateDirectory(facadePath); } var nameTable = new NameTable(); var internFactory = new InternFactory(); try { Dictionary <string, string> seedTypePreferences = ParseSeedTypePreferences(seedTypePreferencesUnsplit); using (var contractHost = new HostEnvironment(nameTable, internFactory)) using (var seedHost = new HostEnvironment(nameTable, internFactory)) { contractHost.LoadErrorTreatment = contractLoadErrorTreatment; seedHost.LoadErrorTreatment = seedLoadErrorTreatment; var contractAssemblies = LoadAssemblies(contractHost, contracts); IReadOnlyDictionary <string, IEnumerable <string> > docIdTable = GenerateDocIdTable(contractAssemblies, inclusionContracts); IAssembly[] seedAssemblies = LoadAssemblies(seedHost, seeds).ToArray(); IAssemblyReference seedCoreAssemblyRef = ((Microsoft.Cci.Immutable.PlatformType)seedHost.PlatformType).CoreAssemblyRef; if (forceZeroVersionSeeds) { // Create a deep copier, copy the seed assemblies, and zero out their versions. var copier = new MetadataDeepCopier(seedHost); for (int i = 0; i < seedAssemblies.Length; i++) { var mutableSeed = copier.Copy(seedAssemblies[i]); mutableSeed.Version = new Version(0, 0, 0, 0); // Copy the modified seed assembly back. seedAssemblies[i] = mutableSeed; if (mutableSeed.Name.UniqueKey == seedCoreAssemblyRef.Name.UniqueKey) { seedCoreAssemblyRef = mutableSeed; } } } var typeTable = GenerateTypeTable(seedAssemblies); var facadeGenerator = new FacadeGenerator(seedHost, contractHost, docIdTable, typeTable, seedTypePreferences, clearBuildAndRevision, buildDesignTimeFacades, assemblyFileVersion); if (partialFacadeAssemblyPath != null) { if (contractAssemblies.Count() != 1) { throw new FacadeGenerationException( "When partialFacadeAssemblyPath is specified, only exactly one corresponding contract assembly can be specified."); } IAssembly contractAssembly = contractAssemblies.First(); IAssembly partialFacadeAssembly = seedHost.LoadAssembly(partialFacadeAssemblyPath); if (contractAssembly.Name != partialFacadeAssembly.Name || contractAssembly.Version.Major != partialFacadeAssembly.Version.Major || contractAssembly.Version.Minor != partialFacadeAssembly.Version.Minor || (!ignoreBuildAndRevisionMismatch && contractAssembly.Version.Build != partialFacadeAssembly.Version.Build) || (!ignoreBuildAndRevisionMismatch && contractAssembly.Version.Revision != partialFacadeAssembly.Version.Revision) || contractAssembly.GetPublicKeyToken() != partialFacadeAssembly.GetPublicKeyToken()) { throw new FacadeGenerationException( string.Format("The partial facade assembly's name, version, and public key token must exactly match the contract to be filled. Contract: {0}, Facade: {1}", contractAssembly.AssemblyIdentity, partialFacadeAssembly.AssemblyIdentity)); } Assembly filledPartialFacade = facadeGenerator.GenerateFacade(contractAssembly, seedCoreAssemblyRef, ignoreMissingTypes, overrideContractAssembly: partialFacadeAssembly); if (filledPartialFacade == null) { Trace.TraceError("Errors were encountered while generating the facade."); return(false); } string pdbLocation = null; if (producePdb) { string pdbFolder = Path.GetDirectoryName(partialFacadeAssemblyPath); pdbLocation = Path.Combine(pdbFolder, contractAssembly.Name + ".pdb"); if (producePdb && !File.Exists(pdbLocation)) { pdbLocation = null; Trace.TraceWarning("No PDB file present for un-transformed partial facade. No PDB will be generated."); } } OutputFacadeToFile(facadePath, seedHost, filledPartialFacade, contractAssembly, pdbLocation); } else { foreach (var contract in contractAssemblies) { Assembly facade = facadeGenerator.GenerateFacade(contract, seedCoreAssemblyRef, ignoreMissingTypes); if (facade == null) { #if !COREFX Debug.Assert(Environment.ExitCode != 0); #endif return(false); } OutputFacadeToFile(facadePath, seedHost, facade, contract); } } } return(true); } catch (FacadeGenerationException ex) { Trace.TraceError(ex.Message); #if !COREFX Debug.Assert(Environment.ExitCode != 0); #endif return(false); } }
public static void RunBclRewriter(string[] args) { #region Parse the command-line arguments. if (!Parser.ParseArgumentsWithUsage(args, typeof(Program))) throw new UsageException(); #endregion #region Figure out paths s_assemblyName = Path.GetFullPath(s_assemblyName); // this has to be specified string outputBaseName = null; if (!String.IsNullOrEmpty(s_output)) { s_output = Path.GetFullPath(s_output); outputBaseName = Path.GetFileNameWithoutExtension(s_output); } else { s_output = Path.Combine(Directory.GetCurrentDirectory(), Path.GetFileNameWithoutExtension(s_assemblyName) + ".small" + Path.GetExtension(s_assemblyName)); outputBaseName = s_assemblyName; } string pdbSourceFile = Path.ChangeExtension(s_assemblyName, "pdb"); string outputPdb = Path.ChangeExtension(s_output, "pdb"); string outputFolder = Path.GetDirectoryName(s_output); // if the user wants to do an in-place rewrite, we copy the file to a temp file if (s_output == s_assemblyName) { String tempPath = s_assemblyName + TempExtension; String tempPdbPath = pdbSourceFile + TempExtension; File.Copy(s_assemblyName, tempPath, true); s_assemblyName = tempPath; if (File.Exists(pdbSourceFile)) { File.Copy(pdbSourceFile, tempPdbPath, true); pdbSourceFile = tempPdbPath; } } if (!Directory.Exists(outputFolder)) Directory.CreateDirectory(outputFolder); #endregion #region Load input files HostEnvironment host = new HostEnvironment(new NameTable(), s_assemblyDependencyPaths, s_referencedAssemblies); IAssembly/*?*/ assembly = host.LoadUnitFrom(s_assemblyName) as IAssembly; // TODO: Handle multimodule assemblies if (assembly == null || assembly == Dummy.Assembly) { throw new UsageException(args[0] + " is not a PE file containing a CLR assembly, or an error occurred when loading it."); } if (!File.Exists(s_includeListFile)) { throw new UsageException(String.Format("ERROR: Can't find code model file '{0}'", s_includeListFile)); } ThinModel model = new ThinModel(new ThinnerOptions(host, new AssemblyIdentity[] { assembly.AssemblyIdentity })); model.LoadModel(s_includeListFile, new ModelReaderOptions(s_platform, s_architecture, s_flavor, s_treatFxInternalAsPublic, s_defines)); #endregion #region Calculate api closure. ConsoleTimer.StartTimer("Calculating api closure"); model.LoadMetadataFrom(assembly); ThinModel apiClosure = model.CalculateApiClosure(); if (s_keepTempFiles) apiClosure.SaveModel(Path.ChangeExtension(s_output, ".apiClosure.xml")); ConsoleTimer.EndTimer("Calculating api closure"); #endregion #region Calculate impl closure. ConsoleTimer.StartTimer("Calculating implementation closure"); apiClosure.LoadMetadataFrom(assembly); ThinModel implClosure = apiClosure.CalculateImplementationClosure(true, FieldOptions.KeepAll); if (s_keepTempFiles) implClosure.SaveModel(Path.ChangeExtension(s_output, ".implClosure.xml")); ConsoleTimer.EndTimer("Calculating implementation closure"); #endregion #region Trim. ConsoleTimer.StartTimer("Trimming assembly"); IncludeSet includeSet = new IncludeSet(); includeSet.LoadFrom(implClosure); var copier = new MetadataDeepCopier(host); Assembly copiedAssembly = copier.Copy(assembly); Trimmer trimmer = new Trimmer(includeSet, true, false, true, host, s_removeSerializable); trimmer.RewriteChildren(copiedAssembly); Assembly mutableAssembly = copiedAssembly; assembly = mutableAssembly; ConsoleTimer.EndTimer("Trimming assembly"); #endregion #region Update assembly name. ConsoleTimer.StartTimer("Updating assembly name"); // If the output assembly name is different, update the internal assembly name to match. AssemblyIdentity originalAssemblyIdentity = mutableAssembly.AssemblyIdentity; if (!outputBaseName.Equals(originalAssemblyIdentity.Name.ToString(), StringComparison.OrdinalIgnoreCase)) { mutableAssembly.Name = host.NameTable.GetNameFor(outputBaseName); mutableAssembly.ModuleName = mutableAssembly.Name; } // If we changed the assembly identity, update references to it. if (!mutableAssembly.AssemblyIdentity.Equals(originalAssemblyIdentity)) { trimmer.UpdateAssemblyReferences(originalAssemblyIdentity, mutableAssembly.AssemblyIdentity); } ConsoleTimer.EndTimer("Updating assembly name"); #endregion #region Write out the assembly ConsoleTimer.StartTimer("Writing assembly"); PdbReader pdbReader = null; PdbWriter pdbWriter = null; if (File.Exists(pdbSourceFile)) { Stream pdbStream = File.OpenRead(pdbSourceFile); pdbReader = new PdbReader(pdbStream, host); pdbWriter = new PdbWriter(outputPdb, pdbReader); Console.WriteLine("Writing pdb: {0}", outputPdb); } Console.WriteLine("Writing assembly: {0}", s_output); FileStream file = File.Create(s_output); try { PeWriter.WritePeToStream(assembly, host, file, pdbReader, pdbReader, pdbWriter); } finally { if (file != null) { file.Dispose(); } if (pdbWriter != null) { pdbWriter.Dispose(); } } ConsoleTimer.EndTimer("Writing assembly"); #endregion }