/// <summary> /// Generate the comparability information for the given assembly. /// </summary> private static AssemblySummary GenerateComparability(CeleriacArgs celeriacArgs, TypeManager typeManager, IMetadataHost host, IModule module, PdbReader pdbReader, ref Assembly mutable) { AssemblySummary comparabilityManager = null; IAssembly assembly = module as IAssembly; mutable = MetadataCopier.DeepCopy(host, assembly); typeManager.SetAssemblyIdentity(UnitHelper.GetAssemblyIdentity(mutable)); if (celeriacArgs.StaticComparability || celeriacArgs.GenerateComparability) { if (celeriacArgs.ComparabilityFile != null) { using (var cmp = File.Open(celeriacArgs.ComparabilityFile, FileMode.Open)) { comparabilityManager = (AssemblySummary) new BinaryFormatter().Deserialize(cmp); } } else { if (celeriacArgs.VerboseMode) { Console.WriteLine("Generating Comparability Information"); } Assembly decompiled = Decompiler.GetCodeModelFromMetadataModel(typeManager.Host, mutable, pdbReader, DecompilerOptions.AnonymousDelegates | DecompilerOptions.Iterators); comparabilityManager = AssemblySummary.MakeSummary(decompiled, typeManager); if (celeriacArgs.VerboseMode) { Console.WriteLine("Finished Generating Comparability Information"); } using (var cmp = File.Open(celeriacArgs.AssemblyPath + CeleriacArgs.ComparabilityFileExtension, FileMode.Create)) { new BinaryFormatter().Serialize(cmp, comparabilityManager); } } } return(comparabilityManager); }
/// <summary> /// Load the PDB reader and pdb file for the source program. /// </summary> private static PdbReader LoadPdbReaderAndFile(CeleriacArgs celeriacArgs, TypeManager typeManager, IModule module, string pdbFile) { #if __MonoCS__ if (celeriacArgs.StaticComparability) { throw new NotSupportedException("Static comparability analysis is not supported on Mono"); } else { Console.Error.WriteLine("WARNING: Program database (PDB) information is not supported on Mono"); Console.Error.WriteLine("Celeriac will attempt to continue, but might fail."); return(null); } #else PdbReader pdbReader = null; try { using (var pdbStream = File.OpenRead(pdbFile)) { pdbReader = new PdbReader(pdbStream, typeManager.Host); } return(pdbReader); } catch (System.IO.IOException ex) { if (celeriacArgs.StaticComparability) { throw new InvalidOperationException("Error loading program database (PDB) file for '" + module.Name.Value + "'. Debug information is required for static comparability analysis.", ex); } else { // It seems to be non-fatal, so print the error and continue. Console.Error.WriteLine("WARNING: Could not load the PDB file for '" + module.Name.Value + "'"); Console.Error.WriteLine("Celeriac will attempt to continue, but might fail."); } return(null); } #endif }
public static MemoryStream RewriteProgramIL(CeleriacArgs celeriacArgs, TypeManager typeManager) { if (String.IsNullOrWhiteSpace(celeriacArgs.AssemblyPath)) { throw new FileNotFoundException("Path to program to be profiled not provided"); } Stream resultStream; var host = typeManager.Host; IModule /*?*/ module = host.LoadUnitFrom(celeriacArgs.AssemblyPath) as IModule; if (module == null || module == Dummy.Module || module == Dummy.Assembly) { throw new FileNotFoundException("Given path is not a PE file containing a CLR" + " assembly, or an error occurred when loading it.", celeriacArgs.AssemblyPath); } if (module.GetAllTypes().Any( type => type.Name.ToString().Equals(ILRewriter.ArgumentStoringClassName))) { throw new InvalidOperationException("Program has already been instrumented."); } string pdbFile = Path.ChangeExtension(module.Location, "pdb"); Assembly mutable = null; using (var pdbReader = LoadPdbReaderAndFile(celeriacArgs, typeManager, module, pdbFile)) { AssemblySummary comparabilityManager = GenerateComparability(celeriacArgs, typeManager, host, module, pdbReader, ref mutable); if (celeriacArgs.GenerateComparability && celeriacArgs.ComparabilityFile == null) { return(null); } ILRewriter mutator = new ILRewriter(host, pdbReader, celeriacArgs, typeManager, comparabilityManager); module = mutator.Visit(mutable, Path.Combine(FindVisitorDir(), VisitorDll)); if (celeriacArgs.EmitNullaryInfo || celeriacArgs.GenerateComparability) { return(null); } // Remove the old PDB file try { File.Delete(pdbFile); } catch (UnauthorizedAccessException) { // If they are running the debugger we might not be able to delete the file // Save the pdb elsewhere in this case. pdbFile = module.Location + ".pdb"; } if (celeriacArgs.SaveProgram != null) { resultStream = new FileStream(celeriacArgs.SaveProgram, FileMode.Create); } else { resultStream = new MemoryStream(); } #if __MonoCS__ // Reading / Writing DEBUG information on Mono is not supported by CCI PdbWriter pdbWriter = null; #else var pdbWriter = new PdbWriter(pdbFile, pdbReader); #endif // Need to not pass in a local scope provider until such time as we have one // that will use the mutator to remap things (like the type of a scope // constant) from the original assembly to the mutated one. using (pdbWriter) { PeWriter.WritePeToStream(module, host, resultStream, pdbReader, null, pdbWriter); } } if (celeriacArgs.SaveProgram != null) { // We aren't going to run the program, so no need to return anything, // but close the file stream. resultStream.Close(); return(null); } else { return((MemoryStream)resultStream); // success } }