예제 #1
0
        private static void AssemblyDefinitionFromAssembly(FileSystemInfo f, DirectoryInfo[] frameworkPaths, out string[] searchDirectories, out AssemblyDefinition assembly)
        {
            // Use an assembly resolver. This ensures that a single resolver is used instead of instantiating
            // a new resolver per-module; it also ensures that we can insert our own search-paths supplied by the
            // caller.
            var assemblyResolver = new DefaultAssemblyResolver();

            foreach (var frameworkPath in frameworkPaths)
            {
                // string path = EnsureBalancedQuotingInString(frameworkPath);
                // if (Directory.Exists(path))
                if (frameworkPath.Exists)
                {
                    assemblyResolver.AddSearchDirectory(frameworkPath.FullName);
                }
            }

            searchDirectories = assemblyResolver.GetSearchDirectories();
            ReaderParameters parameters = new ReaderParameters()
            {
                AssemblyResolver = assemblyResolver
            };

            assembly = AssemblyDefinition.ReadAssembly(f.FullName, parameters);
        }
예제 #2
0
        private static void InstrumentImpl2(FilePath assemblyPath, FilePath projectPath, FilePath projectSnapshotPath)
        {
            var asmResolver = new DefaultAssemblyResolver();

            Array.ForEach(asmResolver.GetSearchDirectories(), asmResolver.RemoveSearchDirectory);
            asmResolver.AddSearchDirectory(FilePathModule.getDirectoryName(assemblyPath).Item);
            var readerParams = new ReaderParameters
            {
                AssemblyResolver = asmResolver,
                ReadSymbols      = true,
                ReadWrite        = true,
            };

            string testRunnerPath = Path.GetFullPath(typeof(R4nd0mApps.TddStud10.TestRuntime.Marker).Assembly.Location);
            var    enterSPMD      = from t in ModuleDefinition.ReadModule(testRunnerPath).GetTypes()
                                    where t.Name == "Marker"
                                    from m in t.Methods
                                    where m.Name == "EnterSequencePoint"
                                    select m;

            Func <string, string> rebaseDocument = s => PathBuilder.rebaseCodeFilePath(projectPath, projectSnapshotPath, FilePath.NewFilePath(s)).Item;

            Logger.LogInfo("Instrumenting {0}.", assemblyPath);

            using (var assembly = AssemblyDefinition.ReadAssembly(assemblyPath.Item, readerParams))
            {
                if (assembly.Name.HasPublicKey)
                {
                    Logger.LogError("Instrumenting signed assemblies is not supported yet: {0}.", assemblyPath);
                }

                /*
                 *  IL_0001: ldstr <assemblyId>
                 *  IL_0006: ldstr <mdtoken>
                 *  IL_000b: ldstr <spid>
                 *  IL_000d: call void R4nd0mApps.TddStud10.TestHost.Marker::ExitUnitTest(string, ldstr, ldstr)
                 */
                MethodReference enterSPMR = assembly.MainModule.ImportReference(enterSPMD.First());

                VisitAllTypes(
                    assembly.Modules,
                    (m, t) =>
                {
                    InstrumentType2(assemblyPath.Item, rebaseDocument, enterSPMR, m, t);
                });

                try
                {
                    assembly.Write(new WriterParameters {
                        WriteSymbols = true, StrongNameKeyPair = null
                    });
                }
                catch
                {
                    Logger.LogInfo("Backing up or instrumentation failed. Attempting to revert back changes to {0}.", assemblyPath);
                    throw;
                }
            }
        }
예제 #3
0
        /// <summary>Adds all subdirectories to the search directories for the resolver to look in.</summary>
        public void RecurseSearchDirectories()
        {
            var directories = resolver
                              .GetSearchDirectories()
                              .Select(d => new DirectoryInfo(d))
                              .Where(d => d.Exists)
                              .Select(d => d.FullName)
                              .ToDictionary(d => d, d => d);

            var subdirs = directories.Keys
                          .SelectMany(d => Directory.GetDirectories(d, ".", SearchOption.AllDirectories))
                          .Where(d => !directories.ContainsKey(d));

            foreach (var dir in subdirs)
            {
                resolver.AddSearchDirectory(dir);
            }
        }
예제 #4
0
        public static void WeaveTestAssembly()
        {
            // Assembly has already been weaved as part of this run and doesn't need to be done again
            if (WeavedAssembly != null)
            {
                return;
            }

            var currentPath = AppDomain.CurrentDomain.BaseDirectory + @"\Obleak.Fody.Test.dll";

            var beforePath         = Path.GetFullPath(currentPath);
            var beforePdb          = beforePath.Replace(".dll", ".pdb");
            var weavedAssemblyPath = beforePath.Replace(".dll", "2.dll");
            var weavedPdbPath      = beforePath.Replace(".dll", "2.pdb");

            File.Copy(beforePath, weavedAssemblyPath, true);
            File.Copy(beforePdb, weavedPdbPath, true);

            var resolver = new DefaultAssemblyResolver();

            foreach (var dir in resolver.GetSearchDirectories())
            {
                resolver.RemoveSearchDirectory(dir);
            }

            resolver.AddSearchDirectory(AppDomain.CurrentDomain.BaseDirectory);

            var errors   = new List <string>();
            var warnings = new List <string>();

            using (var symbolStream = File.OpenRead(weavedPdbPath))
            {
                var readerParameters = new ReaderParameters
                {
                    AssemblyResolver     = resolver,
                    ReadSymbols          = true,
                    SymbolStream         = symbolStream,
                    SymbolReaderProvider = new PdbReaderProvider()
                };

                var moduleDefinition = ModuleDefinition.ReadModule(weavedAssemblyPath, readerParameters);

                var subscriptionWeavingTask = new ObleakSubscriptionWeaver
                {
                    ModuleDefinition = moduleDefinition,
                    LogInfo          = s => warnings.Add(s),
                    LogError         = s => errors.Add(s),
                };

                subscriptionWeavingTask.Execute();

                if (errors.Any())
                {
                    throw new Exception("Errors raised by the weaving process: " + string.Join(", ", errors));
                }

                var reactiveCommandObleakTask = new ObleakReactiveCommandWeaver
                {
                    ModuleDefinition = moduleDefinition,
                    LogInfo          = s => warnings.Add(s),
                    LogError         = s => errors.Add(s),
                };

                reactiveCommandObleakTask.Execute();

                if (errors.Any())
                {
                    throw new Exception("Errors raised by the weaving process: " + string.Join(", ", errors));
                }

                moduleDefinition.Write(weavedAssemblyPath);
            }
            WeavedAssembly = Assembly.LoadFile(weavedAssemblyPath);
        }
예제 #5
0
    public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly)
    {
        OutputDebugString($"{compiledAssembly.Name}: Start patching...");

        var msgs = new System.Collections.Generic.List <Unity.CompilationPipeline.Common.Diagnostics.DiagnosticMessage>();

        try {
            using (var stream = new MemoryStream(compiledAssembly.InMemoryAssembly.PeData)) {
                var resolver = new DefaultAssemblyResolver();
                foreach (var path in compiledAssembly.References)
                {
                    var dir = Path.GetDirectoryName(path);
                    if (resolver.GetSearchDirectories().Contains(dir))
                    {
                        continue;
                    }

                    OutputDebugString($"{compiledAssembly.Name}: Search in {dir}");
                    resolver.AddSearchDirectory(dir);
                }

                var readerParameters = new ReaderParameters()
                {
                    AssemblyResolver     = resolver,
                    SymbolStream         = new MemoryStream(compiledAssembly.InMemoryAssembly.PdbData),
                    SymbolReaderProvider = new PdbReaderProvider(),
                    ReadSymbols          = true,
                    ReadWrite            = true,
                };

                OutputDebugString($"{compiledAssembly.Name}: Read assembly...");
                using (var assembly = AssemblyDefinition.ReadAssembly(stream, readerParameters)) {
                    OutputDebugString($"{compiledAssembly.Name}: Patching...");

                    var rpcProcessor    = new RpcPostProcessor(assembly.MainModule);
                    var anythingChanged = rpcProcessor.Process(assembly.MainModule);
                    if (!anythingChanged)
                    {
                        OutputDebugString($"{compiledAssembly.Name}: NOTHING CHANGED");
                        return(new ILPostProcessResult(compiledAssembly.InMemoryAssembly));
                    }

                    using (var outStream = new MemoryStream()) {
                        using (var outSymbolStream = new MemoryStream()) {
                            var writeParams = new WriterParameters()
                            {
                                SymbolStream         = outSymbolStream,
                                SymbolWriterProvider = new PdbWriterProvider(),
                                WriteSymbols         = true
                            };
                            assembly.Write(outStream, writeParams);

                            OutputDebugString($"{compiledAssembly.Name}: SUCCESS");

                            return(new ILPostProcessResult(new InMemoryAssembly(outStream.ToArray(), outSymbolStream.ToArray()), msgs));
                        }
                    }
                }
            }
        } catch (System.Exception e) {
            var msg = new Unity.CompilationPipeline.Common.Diagnostics.DiagnosticMessage();
            msg.DiagnosticType = Unity.CompilationPipeline.Common.Diagnostics.DiagnosticType.Error;
            msg.MessageData    = e.Message;
            msgs.Add(msg);

            OutputDebugString($"{compiledAssembly.Name}: {e.Message}");
            OutputDebugString($"{compiledAssembly.Name}: {e.StackTrace}");
            return(new ILPostProcessResult(null, msgs));
        }
    }
예제 #6
0
        private static void InstrumentImpl(IRunExecutorHost host, RunStartParams rsp, Func <DocumentLocation, IEnumerable <DTestCase> > findTest)
        {
            var timeFilter      = rsp.StartTime;
            var solutionRoot    = Path.GetDirectoryName(rsp.Solution.Path.Item);
            var buildOutputRoot = rsp.Solution.BuildRoot.Item;

            Logger.LogInfo(
                "Instrumenting: Time filter - {0}, Build output root - {1}.",
                timeFilter.ToLocalTime(),
                buildOutputRoot);

            System.Reflection.StrongNameKeyPair snKeyPair = null;
            var snKeyFile = Directory.EnumerateFiles(solutionRoot, "*.snk").FirstOrDefault();

            if (snKeyFile != null)
            {
                snKeyPair = new System.Reflection.StrongNameKeyPair(File.ReadAllBytes(snKeyFile));
                Logger.LogInfo("Using strong name from {0}.", snKeyFile);
            }

            var asmResolver = new DefaultAssemblyResolver();

            Array.ForEach(asmResolver.GetSearchDirectories(), asmResolver.RemoveSearchDirectory);
            asmResolver.AddSearchDirectory(buildOutputRoot);
            var readerParams = new ReaderParameters
            {
                AssemblyResolver = asmResolver,
                ReadSymbols      = true,
            };

            string testRunnerPath = Path.GetFullPath(typeof(R4nd0mApps.TddStud10.TestRuntime.Marker).Assembly.Location);
            var    enterSPMD      = from t in ModuleDefinition.ReadModule(testRunnerPath).GetTypes()
                                    where t.Name == "Marker"
                                    from m in t.Methods
                                    where m.Name == "EnterSequencePoint"
                                    select m;

            var exitUTMD = from t in ModuleDefinition.ReadModule(testRunnerPath).GetTypes()
                           where t.Name == "Marker"
                           from m in t.Methods
                           where m.Name == "ExitUnitTest"
                           select m;

            Func <string, string> rebaseDocument = s => PathBuilder.rebaseCodeFilePath(rsp.Solution.Path, rsp.Solution.SnapshotPath, FilePath.NewFilePath(s)).Item;

            Engine.Engine.FindAndExecuteForEachAssembly(
                host,
                buildOutputRoot,
                timeFilter,
                (string assemblyPath) =>
            {
                Logger.LogInfo("Instrumenting {0}.", assemblyPath);

                var assembly = AssemblyDefinition.ReadAssembly(assemblyPath, readerParams);
                var hasSn    = assembly.Name.HasPublicKey;

                /*
                 * IL_0001: ldstr <assemblyId>
                 * IL_0006: ldstr <mdtoken>
                 * IL_000b: ldstr <spid>
                 * IL_000d: call void R4nd0mApps.TddStud10.TestHost.Marker::ExitUnitTest(string, ldstr, ldstr)
                 */
                MethodReference enterSPMR = assembly.MainModule.Import(enterSPMD.First());
                MethodReference exitUTMR  = assembly.MainModule.Import(exitUTMD.First());

                VisitAllTypes(
                    assembly.Modules,
                    (m, t) =>
                {
                    InstrumentType(rsp, findTest, assemblyPath, rebaseDocument, enterSPMR, exitUTMR, m, t);
                });

                var backupAssemblyPath = Path.ChangeExtension(assemblyPath, ".original");
                File.Delete(backupAssemblyPath);
                File.Move(assemblyPath, backupAssemblyPath);
                try
                {
                    assembly.Write(assemblyPath, new WriterParameters {
                        WriteSymbols = true, StrongNameKeyPair = hasSn ? snKeyPair : null
                    });
                }
                catch
                {
                    Logger.LogInfo("Backing up or instrumentation failed. Attempting to revert back changes to {0}.", assemblyPath);
                    File.Delete(assemblyPath);
                    File.Move(backupAssemblyPath, assemblyPath);
                    throw;
                }
            },
                1);
        }
        private NAssemblySource LoadAssembly(ConfigSourceGroup group, string source)
        {
            var dirPath          = Path.GetDirectoryName(source);
            var assemblyResolver = new DefaultAssemblyResolver();

            // Remove any default search path
            assemblyResolver.RemoveSearchDirectory(".");
            assemblyResolver.RemoveSearchDirectory("bin");

            // Search from assembly directory
            assemblyResolver.AddSearchDirectory(dirPath);

            // Add additional search directory
            foreach (var searchDirectory in group.SearchDirectories)
            {
                assemblyResolver.AddSearchDirectory(searchDirectory);
            }

            var parameters = new ReaderParameters(ReadingMode.Immediate)
            {
                AssemblyResolver = assemblyResolver
            };

            assemblyResolver.ResolveFailure += (sender, reference) =>
            {
                var searchDirectories = assemblyResolver.GetSearchDirectories();
                foreach (var directory in searchDirectories)
                {
                    var tryPath = Path.Combine(directory, reference.Name + ".winmd");
                    if (!File.Exists(tryPath))
                    {
                        continue;
                    }

                    try
                    {
                        var winmdAssembly = AssemblyDefinition.ReadAssembly(tryPath, parameters);
                        if (winmdAssembly != null)
                        {
                            return(winmdAssembly);
                        }
                    }
                    catch
                    {
                        // Failed... fall thru and try the next one.
                    }
                }

                // Log an error if we can't find the assembly. Mono.Cecil will throw an exception just after returning from
                // this callback
                Logger.Error("Failed to resolve {0}", reference.FullName);
                return(null);
            };

            var assemblyDefinition = AssemblyDefinition.ReadAssembly(source, parameters);
            var assemblySource     = new NAssemblySource(assemblyDefinition)
            {
                Filename   = source,
                MergeGroup = group.MergeGroup
            };

            return(assemblySource);
        }
예제 #8
0
        /// <summary>Creates an ILNode-Tree representing the structure of the given Assembly
        /// and stores it in the ModuleList Dictionary with the AssemblyDefinition name as key.</summary>
        /// <param name="assDef">The AssemblyDefinition which should be loaded into the searchlist</param>
        /// <param name="subResolveDepth">When the given AssemblyDefinition uses references to other Assemblys
        /// the method will add them recursivly to the given depth</param>
        public void LoadAssembly(AssemblyDefinition assDef, int subResolveDepth = 0)
        {
            if (assDef == null)
            {
                throw new ArgumentNullException(nameof(assDef));
            }
            if (subResolveDepth < 0)
            {
                throw new ArgumentException(nameof(subResolveDepth) + " must be non-negative.");
            }
            if (IsModuleLoaded(assDef.Name.Name))
            {
                return;
            }

            ILNode ilParent = new ILNode(assDef.Name.Name, assDef.FullName, assDef, StructureView.Structure);             // StructureView.Module

            AddModule(assDef.Name.Name, ilParent);

            foreach (ModuleDefinition ModDef in assDef.Modules)
            {
                ILNode tnModDef             = ilParent.Add(ModDef.Name, ModDef.Name, ModDef, StructureView.Structure);
                DefaultAssemblyResolver dar = (DefaultAssemblyResolver)ModDef.AssemblyResolver;
                Array.ForEach(dar.GetSearchDirectories(), dar.RemoveSearchDirectory);
                dar.AddSearchDirectory(Path.GetDirectoryName(dataStruct.AssemblyLocation));

                // Subresolving references
                foreach (AssemblyNameReference anr in ModDef.AssemblyReferences)
                {
                    try
                    {
                        AssemblyDefinition AssSubRef = ModDef.AssemblyResolver.Resolve(anr);
                        tnModDef.Add(anr.Name, AssSubRef.FullName, AssSubRef, StructureView.Structure);
                        if (subResolveDepth > 0)
                        {
                            LoadAssembly(AssSubRef, subResolveDepth - 1);
                        }
                    }
                    catch { Log.Write(Log.Level.Warning, $"AssemblyReference \"{anr.Name}\" couldn't be found for \"{ ModDef.Name}\""); }
                }

                Dictionary <string, ILNode> nsDict = new Dictionary <string, ILNode>();
                foreach (TypeDefinition TypDef in ModDef.Types)
                {
                    string nsstr = TypDef.Namespace;
                    ILNode tnAssemblyContainer;
                    if (!nsDict.ContainsKey(nsstr))
                    {
                        string displaystr = string.IsNullOrEmpty(nsstr) ? "<Default Namespace>" : nsstr;
                        tnAssemblyContainer = ilParent.Add(displaystr, displaystr, new NamespaceHolder(displaystr), StructureView.Namesp);
                        nsDict.Add(nsstr, tnAssemblyContainer);
                    }
                    else
                    {
                        tnAssemblyContainer = nsDict[nsstr];
                    }

                    ILNode tnTypDef = tnAssemblyContainer.Add(TypDef.Name, TypDef.FullName, TypDef, StructureView.Classes);
                    LoadSubItemsRecursive(tnTypDef, TypDef);
                }
            }
            ilParent.Sort();

            if (subResolveDepth == 0)             // If this is the last LoadAssembly recursion call then invoke the callback
            {
                OnModuleChanged?.Invoke(this);
            }
        }
예제 #9
0
        private static bool TryProcessAssembly(string inputPath, string outputPath)
        {
            bool processed = false;

            try
            {
                var asmResolver = new DefaultAssemblyResolver();
                foreach (var path in asmResolver.GetSearchDirectories())
                {
                    asmResolver.RemoveSearchDirectory(path);
                }

                asmResolver.AddSearchDirectory(Path.GetDirectoryName(inputPath));
                using (var assemblyDefinition = AssemblyDefinition.ReadAssembly(inputPath, new ReaderParameters {
                    AssemblyResolver = asmResolver
                }))
                {
                    var lstDefinitionsDefs = new List <DefinitionItem>();
                    var moduleDefinition   = assemblyDefinition.MainModule;

                    // Extract direct definitions
                    foreach (var definition in Definitions)
                    {
                        if (definition.TargetAssembly != assemblyDefinition.Name.Name)
                        {
                            continue;
                        }

                        if (assemblyDefinition.Name.Version is not null)
                        {
                            var minVersion = new Version(definition.TargetMinimumMajor, definition.TargetMinimumMinor, definition.TargetMinimumPatch);
                            var maxVersion = new Version(definition.TargetMaximumMajor, definition.TargetMaximumMinor, definition.TargetMaximumPatch);

                            if (assemblyDefinition.Name.Version < minVersion)
                            {
                                continue;
                            }

                            if (assemblyDefinition.Name.Version > maxVersion)
                            {
                                continue;
                            }
                        }

                        var typeDefinition = moduleDefinition.Types.FirstOrDefault(t => t.FullName == definition.TargetType);
                        if (typeDefinition is null && moduleDefinition.HasExportedTypes)
                        {
                            var exportedType = moduleDefinition.ExportedTypes.FirstOrDefault(eType => eType.FullName == definition.TargetType);
                            if (exportedType is not null)
                            {
                                try
                                {
                                    typeDefinition = exportedType.Resolve();
                                }
                                catch
                                {
                                    // ...
                                }
                            }
                        }

                        if (typeDefinition is not null)
                        {
                            RetrieveMethodsInTypeDefinition(typeDefinition, definition, lstDefinitionsDefs, assemblyDefinition);
                        }
                    }

                    // Extract derived definitions
                    var assemblyReferences = moduleDefinition.AssemblyReferences;
                    foreach (var assemblyReference in assemblyReferences)
                    {
                        foreach (var definition in DerivedDefinitions)
                        {
                            if (definition.TargetAssembly != assemblyReference.Name)
                            {
                                continue;
                            }

                            var minVersion = new Version(definition.TargetMinimumMajor, definition.TargetMinimumMinor, definition.TargetMinimumPatch);
                            var maxVersion = new Version(definition.TargetMaximumMajor, definition.TargetMaximumMinor, definition.TargetMaximumPatch);

                            if (assemblyReference.Version < minVersion)
                            {
                                continue;
                            }

                            if (assemblyReference.Version > maxVersion)
                            {
                                continue;
                            }

                            var asmName = moduleDefinition.Assembly.FullName;

                            foreach (var typeDefinition in moduleDefinition.Types)
                            {
                                var baseTypeReference = typeDefinition.BaseType;
                                if (baseTypeReference != null && baseTypeReference.FullName == definition.TargetType)
                                {
                                    RetrieveMethodsInTypeDefinition(typeDefinition, definition, lstDefinitionsDefs, assemblyDefinition);
                                }
                            }
                        }
                    }

                    if (lstDefinitionsDefs.Count == 0)
                    {
                        return(false);
                    }

                    AnsiConsole.WriteLine($"{assemblyDefinition.Name.FullName} => {lstDefinitionsDefs.Count}");
                    if (ProcessDefinitions(moduleDefinition, lstDefinitionsDefs))
                    {
                        if ((moduleDefinition.Attributes & ModuleAttributes.ILLibrary) == ModuleAttributes.ILLibrary)
                        {
                            moduleDefinition.Architecture = TargetArchitecture.I386;
                            moduleDefinition.Attributes  &= ~ModuleAttributes.ILLibrary;
                            moduleDefinition.Attributes  |= ModuleAttributes.ILOnly;
                        }

                        assemblyDefinition.Write(outputPath);
                        processed = true;
                    }
                }
            }
            catch (BadImageFormatException)
            {
                return(false);
            }
            catch (Exception ex)
            {
                Utils.WriteError($"{inputPath}: {ex.Message}");
                return(false);
            }
            finally
            {
                if (!processed)
                {
                    File.Copy(inputPath, outputPath, true);
                }
            }

            return(true);

            void RetrieveMethodsInTypeDefinition(TypeDefinition typeDefinition, NativeCallTargetDefinition definition, List <DefinitionItem> lstDefinitionsDefs, AssemblyDefinition assemblyDefinition)
            {
                foreach (var mDefinition in typeDefinition.Methods.Where(m => m.Name == definition.TargetMethod))
                {
                    var lstParameters = mDefinition.Parameters;
                    if (lstParameters.Count != definition.TargetSignatureTypesLength - 1)
                    {
                        continue;
                    }

                    bool parameters = true;
                    var  ptr        = definition.TargetSignatureTypes;
                    for (var i = 0; i < definition.TargetSignatureTypesLength; i++)
                    {
                        var localPtr    = Marshal.ReadIntPtr(ptr);
                        var localString = Marshal.PtrToStringUni(localPtr);
                        ptr += Marshal.SizeOf(typeof(IntPtr));

                        if (localString == "_")
                        {
                            continue;
                        }

                        if (i == 0)
                        {
                            if (mDefinition.ReturnType.FullName != localString)
                            {
                                parameters = false;
                                break;
                            }
                        }
                        else if (lstParameters[i - 1].ParameterType.FullName != localString)
                        {
                            parameters = false;
                            break;
                        }
                    }

                    if (parameters)
                    {
                        var methodDefinition = mDefinition;
                        var integrationType  = TracerAssembly.GetType(definition.IntegrationType, false);
                        if (integrationType is not null)
                        {
                            lstDefinitionsDefs.Add(new DefinitionItem(assemblyDefinition, typeDefinition, methodDefinition, integrationType, definition));
                        }

                        break;
                    }
                }
            }
        }