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);
        }
Пример #3
0
        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);
            }
        }
Пример #4
0
        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);
            }
        }
Пример #5
0
    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);
              }
            }
          }
        }
      }
    }
Пример #6
0
    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);
    }
Пример #7
0
        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
            }
        }
Пример #8
0
            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);
            }
Пример #9
0
        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();
                }
            }));
        }
Пример #10
0
        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);
                            }
                        }
                    }
                }
            }
        }
Пример #11
0
 /// <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));
 }
Пример #12
0
        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);
        }
Пример #13
0
        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
        }
Пример #14
0
        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
            }
        }
Пример #15
0
    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;
    }
Пример #16
0
            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;
            }
Пример #17
0
        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);
            }
        }
Пример #18
0
        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
        }