/// <summary> /// Compiles and decompiles a source code. /// </summary> /// <param name="code">The source code to copile.</param> /// <returns>The decompilation result of compiled source code.</returns> static string RoundtripCode(string code) { DecompilerSettings settings = new DecompilerSettings(); settings.FullyQualifyAmbiguousTypeNames = false; AssemblyDefinition assembly = Compile(code); AstBuilder decompiler = new AstBuilder(new DecompilerContext(assembly.MainModule) { Settings = settings }); decompiler.AddAssembly(assembly); new Helpers.RemoveCompilerAttribute().Run(decompiler.CompilationUnit); StringWriter output = new StringWriter(); decompiler.GenerateCode(new PlainTextOutput(output)); return output.ToString(); }
public CallBuilder(ExpressionBuilder expressionBuilder, IDecompilerTypeSystem typeSystem, DecompilerSettings settings) { this.expressionBuilder = expressionBuilder; this.resolver = expressionBuilder.resolver; this.settings = settings; this.typeSystem = typeSystem; }
async Task Run([CallerMemberName] string testName = null, CompilerOptions options = CompilerOptions.UseDebug, DecompilerSettings settings = null) { var vbFile = Path.Combine(TestCasePath, testName + ".vb"); var csFile = Path.Combine(TestCasePath, testName + ".cs"); var exeFile = Path.Combine(TestCasePath, testName) + Tester.GetSuffix(options) + ".exe"; if (options.HasFlag(CompilerOptions.Library)) { exeFile = Path.ChangeExtension(exeFile, ".dll"); } var executable = await Tester.CompileVB(vbFile, options | CompilerOptions.ReferenceVisualBasic, exeFile).ConfigureAwait(false); var decompiled = await Tester.DecompileCSharp(executable.PathToAssembly, settings).ConfigureAwait(false); CodeAssert.FilesAreEqual(csFile, decompiled, Tester.GetPreprocessorSymbols(options).ToArray()); }
public static int ShowDuplicateImports(FileInfo winmd, IConsole console) { DecompilerSettings settings = new DecompilerSettings() { ThrowOnAssemblyResolveErrors = false }; DecompilerTypeSystem winmd1 = CreateTypeSystemFromFile(winmd.FullName, settings); Dictionary <string, List <string> > dllImportsToClassNames = new Dictionary <string, List <string> >(); foreach (var type1 in winmd1.GetTopLevelTypeDefinitions()) { if (type1.FullName == "<Module>") { continue; } if (type1.ParentModule != winmd1.MainModule) { continue; } if (type1.Kind != TypeKind.Class) { continue; } foreach (var method in type1.GetMethods()) { if (!method.IsStatic) { continue; } var dllImportAttr = method.GetAttribute(KnownAttribute.DllImport); if (dllImportAttr != null) { string entryPoint = method.Name; var dllName = (string)(dllImportAttr.FixedArguments[0].Value); var entryPointVar = dllImportAttr.NamedArguments.FirstOrDefault(a => a.Name == "EntryPoint"); if (entryPointVar.Name != null) { entryPoint = (string)entryPointVar.Value; } string fullImport = $"{dllName}:{entryPoint}"; string archInfo = GetArchInfo(method.GetAttributes()); if (!string.IsNullOrEmpty(archInfo)) { fullImport += $"({archInfo})"; } if (!dllImportsToClassNames.TryGetValue(fullImport, out var classNames)) { classNames = new List <string>(); dllImportsToClassNames[fullImport] = classNames; } classNames.Add(type1.FullName); } } } bool dupsFound = false; foreach (var pair in dllImportsToClassNames) { if (pair.Value.Count > 1) { if (dupsFound == false) { dupsFound = true; console.Out.Write("Duplicated imports detected:\r\n"); } pair.Value.Sort(); console?.Out.Write($"{pair.Key}\r\n"); foreach (var imp in pair.Value) { console?.Out.Write($" {imp}\r\n"); } } } if (!dupsFound) { console.Out.Write("No duplicate imports found.\r\n"); } return(dupsFound ? -1 : 0); }
public static int ShowDuplicateConstants(FileInfo winmd, IConsole console) { DecompilerSettings settings = new DecompilerSettings() { ThrowOnAssemblyResolveErrors = false }; DecompilerTypeSystem winmd1 = CreateTypeSystemFromFile(winmd.FullName, settings); Dictionary <string, List <string> > nameToOwner = new Dictionary <string, List <string> >(); foreach (var type in winmd1.GetTopLevelTypeDefinitions()) { if (type.FullName == "<Module>") { continue; } if (type.ParentModule != winmd1.MainModule) { continue; } // Skip enums marked as a scoped enum (like a C++ class enum). // We don't count these in the duplicated constants if (type.Kind == TypeKind.Enum) { if (type.GetAttributes().Any(a => a.AttributeType.Name == "ScopedEnumAttribute")) { continue; } } if (type.Kind == TypeKind.Enum || (type.Kind == TypeKind.Class && type.Name == "Apis")) { foreach (var field in type.GetFields(options: GetMemberOptions.IgnoreInheritedMembers)) { if (field.Name == "value__") { continue; } if (!nameToOwner.TryGetValue(field.Name, out var owners)) { owners = new List <string>(); nameToOwner[field.Name] = owners; } owners.Add(type.FullName); } } } bool dupsFound = false; foreach (var pair in nameToOwner) { if (pair.Value.Count > 1) { if (dupsFound == false) { dupsFound = true; console.Out.Write("Duplicate constants/enum names detected:\r\n"); } pair.Value.Sort(); console?.Out.Write($"{pair.Key}\r\n"); foreach (var owner in pair.Value) { console?.Out.Write($" {owner}\r\n"); } } } if (!dupsFound) { console.Out.Write("No duplicate constants/enum names found.\r\n"); } return(dupsFound ? -1 : 0); }
public StatementBuilder(IDecompilerTypeSystem typeSystem, ITypeResolveContext decompilationContext, IMethod currentMethod, ILFunction currentFunction, DecompilerSettings settings, CancellationToken cancellationToken) { Debug.Assert(typeSystem != null && decompilationContext != null && currentMethod != null); this.exprBuilder = new ExpressionBuilder(typeSystem, decompilationContext, settings, cancellationToken); this.currentFunction = currentFunction; this.currentMethod = currentMethod; this.settings = settings; this.cancellationToken = cancellationToken; }
public ILTransformContext(ILFunction function, IDecompilerTypeSystem typeSystem, IDebugInfoProvider debugInfo, DecompilerSettings settings = null) { this.Function = function ?? throw new ArgumentNullException(nameof(function)); this.TypeSystem = typeSystem ?? throw new ArgumentNullException(nameof(typeSystem)); this.Settings = settings ?? new DecompilerSettings(); this.DebugInfo = debugInfo; Stepper = new Stepper(); }
public static async Task <List <ReferenceSegment> > DecompileAsync(TextEditor data, AssemblyLoader assemblyLoader, Func <CSharpDecompiler, SyntaxTree> decompile, DecompilerSettings settings = null, DecompileFlags flags = null) { if (data == null) { throw new ArgumentNullException(nameof(data)); } if (assemblyLoader == null) { throw new ArgumentNullException(nameof(assemblyLoader)); } return(await Task.Run(async delegate { settings = settings ?? GetDecompilerSettings(data, publicOnly: flags.PublicOnly); var csharpDecompiler = assemblyLoader.CSharpDecompiler; try { var syntaxTree = decompile(csharpDecompiler); if (!flags.MethodBodies) { MethodBodyRemoveVisitor.RemoveMethodBodies(syntaxTree); } return await Runtime.RunInMainThread(delegate { if (data.IsDisposed) { return new List <ReferenceSegment> (); } var output = new ColoredCSharpFormatter(data); TokenWriter tokenWriter = new TextTokenWriter(output, settings, csharpDecompiler.TypeSystem) { FoldBraces = settings.FoldBraces }; var formattingPolicy = settings.CSharpFormattingOptions; syntaxTree.AcceptVisitor(new CSharpOutputVisitor(tokenWriter, formattingPolicy)); output.SetDocumentData(); return output.ReferencedSegments; }); } catch (Exception e) { await Runtime.RunInMainThread(delegate { data.InsertText(data.Length, "/* decompilation failed: \n" + e + " */"); }); } return new List <ReferenceSegment> (); })); }
async Task RunInternal(string dir, string fileToRoundtrip, Action <string> testAction, LanguageVersion languageVersion, string snkFilePath = null, bool useOldProjectFormat = false) { if (!Directory.Exists(TestDir)) { Assert.Ignore($"Assembly-roundtrip test ignored: test directory '{TestDir}' needs to be checked out separately." + Environment.NewLine + $"git clone https://github.com/icsharpcode/ILSpy-tests \"{TestDir}\""); } string inputDir = Path.Combine(TestDir, dir); string decompiledDir = inputDir + "-decompiled"; string outputDir = inputDir + "-output"; if (inputDir.EndsWith("TestCases")) { // make sure output dir names are unique so that we don't get trouble due to parallel test execution decompiledDir += Path.GetFileNameWithoutExtension(fileToRoundtrip) + "_" + languageVersion.ToString(); outputDir += Path.GetFileNameWithoutExtension(fileToRoundtrip) + "_" + languageVersion.ToString(); } ClearDirectory(decompiledDir); ClearDirectory(outputDir); string projectFile = null; foreach (string file in Directory.EnumerateFiles(inputDir, "*", SearchOption.AllDirectories)) { if (!file.StartsWith(inputDir + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase)) { Assert.Fail($"Unexpected file name: {file}"); } string relFile = file.Substring(inputDir.Length + 1); Directory.CreateDirectory(Path.Combine(outputDir, Path.GetDirectoryName(relFile))); if (relFile.Equals(fileToRoundtrip, StringComparison.OrdinalIgnoreCase)) { Console.WriteLine($"Decompiling {fileToRoundtrip}..."); Stopwatch w = Stopwatch.StartNew(); using (var fileStream = new FileStream(file, FileMode.Open, FileAccess.Read)) { PEFile module = new PEFile(file, fileStream, PEStreamOptions.PrefetchEntireImage); var resolver = new TestAssemblyResolver(file, inputDir, module.Metadata.DetectTargetFrameworkId()); resolver.AddSearchDirectory(inputDir); resolver.RemoveSearchDirectory("."); // use a fixed GUID so that we can diff the output between different ILSpy runs without spurious changes var projectGuid = Guid.Parse("{127C83E4-4587-4CF9-ADCA-799875F3DFE6}"); var settings = new DecompilerSettings(languageVersion); if (useOldProjectFormat) { settings.UseSdkStyleProjectFormat = false; } var decompiler = new TestProjectDecompiler(projectGuid, resolver, resolver, settings); if (snkFilePath != null) { decompiler.StrongNameKeyFile = Path.Combine(inputDir, snkFilePath); } decompiler.DecompileProject(module, decompiledDir); Console.WriteLine($"Decompiled {fileToRoundtrip} in {w.Elapsed.TotalSeconds:f2}"); projectFile = Path.Combine(decompiledDir, module.Name + ".csproj"); } } else { File.Copy(file, Path.Combine(outputDir, relFile)); } } Assert.IsNotNull(projectFile, $"Could not find {fileToRoundtrip}"); await Compile(projectFile, outputDir); testAction(outputDir); }
public CSharpVBDecompilerSettings(DecompilerSettings decompilerSettings = null) { this.decompilerSettings = decompilerSettings ?? new DecompilerSettings(); options = CreateOptions().ToArray(); }
/// <summary> /// Gets/sets an optional state of a decompiler text view. /// </summary> /// <remarks> /// This state is used to restore test view's state when decompilation is started by Go Back/Forward action. /// </remarks> //public ICSharpCode.ILSpy.TextView.DecompilerTextViewState TextViewState { get; set; } public DecompilationOptions() { //this.DecompilerSettings = DecompilerSettingsPanel.CurrentDecompilerSettings; this.DecompilerSettings = new DecompilerSettings(); this.FullDecompilation = false; }
private static string Decompile(Assemblies.AssemblyDefinition asm, IEnumerable<TypeDefinition> types) { DecompilerSettings settings = new DecompilerSettings(); settings.FullyQualifyAmbiguousTypeNames = false; var ctx = new DecompilerContext(asm.MainModule) { Settings = settings }; var decompiler = new AstBuilder(ctx); foreach (var t in types) { decompiler.AddType(t); } new Helpers.RemoveCompilerAttribute().Run(decompiler.CompilationUnit); var output = new StringWriter(); decompiler.GenerateCode(new PlainTextOutput(output)); return output.ToString().Trim(); }
public static void Decompile(string path) { var asm = AssemblyDefinition.ReadAssembly(path); var settings = new DecompilerSettings(); settings.FullyQualifyAmbiguousTypeNames = false; var ctx = new DecompilerContext(asm.MainModule) { Settings = settings }; var decompiler = new AstBuilder(ctx); decompiler.AddAssembly(asm); new Helpers.RemoveCompilerAttribute().Run(decompiler.CompilationUnit); var output = new StringWriter(); decompiler.GenerateCode(new PlainTextOutput(output)); }
public void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilerSettings options) { AddReferenceWarningMessage(property.Module.Assembly, output); WriteCommentLine(output, TypeToString(property.DeclaringType, includeNamespace: true)); CSharpDecompiler decompiler = CreateDecompiler(property.Module, options); WriteCode(output, options, decompiler.Decompile(property), decompiler.TypeSystem); }
void RunForLibrary([CallerMemberName] string testName = null, AssemblerOptions asmOptions = AssemblerOptions.None, CompilerOptions cscOptions = CompilerOptions.None, DecompilerSettings decompilerSettings = null) { Run(testName, asmOptions | AssemblerOptions.Library, cscOptions | CompilerOptions.Library, decompilerSettings); }
// Extraction of strings private void ExtractEncryptedStrings(object sender, DoWorkEventArgs args) { // Get assembly name from arguments string assemblyName = (string)args.Argument; // Build new payload object Payload payload = new Payload(); // Setup decompiler DecompilerSettings settings = new DecompilerSettings(); settings.FullyQualifyAmbiguousTypeNames = true; var resolver = new DefaultAssemblyResolver(); resolver.AddSearchDirectory(Environment.CurrentDirectory); var parameters = new ReaderParameters { AssemblyResolver = resolver, }; AssemblyDefinition assembly1 = AssemblyDefinition.ReadAssembly(assemblyName); // Add assembly to the decompiler AstBuilder decompiler = new AstBuilder(new DecompilerContext(assembly1.MainModule) { Settings = settings }); decompiler.AddAssembly(assembly1); // Generate the code StringWriter output = new StringWriter(); decompiler.GenerateCode(new PlainTextOutput(output)); // Get the code from the decompiler into a string byte[] byteArray = Encoding.ASCII.GetBytes(output.ToString()); TextReader codeReader = new StreamReader(new MemoryStream(byteArray)); string code = codeReader.ReadToEnd(); // Build regex to extract strings List <string> SharedSecretPatterns = new List <string>() { @"private static string msaltpassss = \""(?<SharedSecret>.+)\"";", @"private static string e1 = \""(?<SharedSecret>.+)\"";" }; List <string> SaltPatterns = new List <string>() { @"private static byte\[\] _salt = Encoding.ASCII.GetBytes\(\""(?<Salt>.+)\""\);" }; List <string> EncryptedStringsPatterns = new List <string>() { @"encc.DecryptStringAES\(\""(?<String>.+)\"",", @"encc.myff11\(\""(?<String>.+)\"",", @"\""(?<String>([A-F0-9]{2})*)\""" }; // Enumerate the shared secret patterns foreach (string SharedSecretPattern in SharedSecretPatterns) { // Match regex Match SharedSecretMatch = Regex.Match(code, SharedSecretPattern); // Check for success if (SharedSecretMatch.Success) { // Extract the value payload.SharedSecret = SharedSecretMatch.Groups["SharedSecret"].Value; break; } } // Enumerate the salt patterns foreach (string SaltPattern in SaltPatterns) { // Match regex Match SaltMatch = Regex.Match(code, SaltPattern); // Check for success if (SaltMatch.Success) { // Extract the value payload.Salt = SaltMatch.Groups["Salt"].Value; break; } } // Enumerate encrypted string patterns foreach (string EncryptedStringsPattern in EncryptedStringsPatterns) { // Match regex MatchCollection StringsMatch = Regex.Matches(code, EncryptedStringsPattern); // Check for success if (StringsMatch.Count > 0) { // Extract the value payload.Strings = StringsMatch.Cast <Match>().Select(m => m.Groups["String"].Value).ToList(); break; } } // Set the payload object as the result args.Result = payload; }
public TestProjectDecompiler(Guid projecGuid, IAssemblyResolver resolver, AssemblyReferenceClassifier assemblyReferenceClassifier, DecompilerSettings settings) : base(settings, projecGuid, resolver, assemblyReferenceClassifier, debugInfoProvider: null) { }
internal static DecompilerSettings CreateDecompilerSettings_DecompileTypeMethods(DecompilerSettings settings, bool useUsingDeclarations, bool showAll) { var s = CreateDecompilerSettings(settings, useUsingDeclarations); // Make sure the ctor is shown if the user tries to edit an empty ctor/cctor s.RemoveEmptyDefaultConstructors = false; if (!showAll) { // Inline all field initialization code s.AllowFieldInitializers = false; } return(s); }
/// <summary> /// Gets whether the specific binary instruction is compatible with a compound operation on the specified type. /// </summary> internal static bool IsBinaryCompatibleWithType(BinaryNumericInstruction binary, IType type, DecompilerSettings settings) { if (binary.IsLifted) { if (!NullableType.IsNullable(type)) { return(false); } type = NullableType.GetUnderlyingType(type); } if (type.Kind == TypeKind.Unknown) { return(false); // avoid introducing a potentially-incorrect compound assignment } else if (type.Kind == TypeKind.Enum) { switch (binary.Operator) { case BinaryNumericOperator.Add: case BinaryNumericOperator.Sub: case BinaryNumericOperator.BitAnd: case BinaryNumericOperator.BitOr: case BinaryNumericOperator.BitXor: break; // OK default: return(false); // operator not supported on enum types } } else if (type.Kind == TypeKind.Pointer) { switch (binary.Operator) { case BinaryNumericOperator.Add: case BinaryNumericOperator.Sub: // ensure that the byte offset is a multiple of the pointer size return(PointerArithmeticOffset.Detect( binary.Right, ((PointerType)type).ElementType, checkForOverflow: binary.CheckForOverflow ) != null); default: return(false); // operator not supported on pointer types } } else if (type.IsKnownType(KnownTypeCode.IntPtr) || type.IsKnownType(KnownTypeCode.UIntPtr)) { // "target.intptr *= 2;" is compiler error, but // "target.intptr *= (nint)2;" works if (settings != null && !settings.NativeIntegers) { // But if native integers are not available, we cannot use compound assignment. return(false); } // The trick with casting the RHS to n(u)int doesn't work for shifts: switch (binary.Operator) { case BinaryNumericOperator.ShiftLeft: case BinaryNumericOperator.ShiftRight: return(false); } } if (binary.Sign != Sign.None) { if (type.IsCSharpSmallIntegerType()) { // C# will use numeric promotion to int, binary op must be signed if (binary.Sign != Sign.Signed) { return(false); } } else { // C# will use sign from type if (type.GetSign() != binary.Sign) { return(false); } } } // Can't transform if the RHS value would be need to be truncated for the LHS type. if (Transforms.TransformAssignment.IsImplicitTruncation(binary.Right, type, null, binary.IsLifted)) { return(false); } return(true); }
public CSharpVBDecompilerSettings(DecompilerSettings?decompilerSettings = null) { this.decompilerSettings = decompilerSettings ?? new DecompilerSettings(); options = CreateOptions().ToArray(); this.decompilerSettings.SettingsVersionChanged += DecompilerSettings_SettingsVersionChanged; }
public static List <ReferenceSegment> Decompile(TextEditor data, AssemblyLoader assemblyLoader, Func <CSharpDecompiler, SyntaxTree> decompile, DecompilerSettings settings = null, DecompileFlags flags = null) { settings = settings ?? GetDecompilerSettings(data, publicOnly: flags.PublicOnly); var csharpDecompiler = assemblyLoader.CSharpDecompiler; try { var syntaxTree = decompile(csharpDecompiler); if (!flags.MethodBodies) { MethodBodyRemoveVisitor.RemoveMethodBodies(syntaxTree); } var output = new ColoredCSharpFormatter(data); TokenWriter tokenWriter = new TextTokenWriter(output, settings, csharpDecompiler.TypeSystem) { FoldBraces = settings.FoldBraces }; var formattingPolicy = settings.CSharpFormattingOptions; syntaxTree.AcceptVisitor(new CSharpOutputVisitor(tokenWriter, formattingPolicy)); output.SetDocumentData(); return(output.ReferencedSegments); } catch (Exception e) { data.InsertText(data.Length, "/* decompilation failed: \n" + e + " */"); } return(null); }
public static int CompareWinmds(FileInfo first, FileInfo second, string exclusions, IConsole console) { bool same = true; DecompilerSettings settings = new DecompilerSettings() { ThrowOnAssemblyResolveErrors = false }; DecompilerTypeSystem winmd1 = CreateTypeSystemFromFile(first.FullName, settings); DecompilerTypeSystem winmd2 = CreateTypeSystemFromFile(second.FullName, settings); var winmd1Types = GetSelfDefinedWinmdToplevelTypes(winmd1); var winmd2Types = GetSelfDefinedWinmdToplevelTypes(winmd2); same &= CompareTypes(winmd1Types, winmd2Types, console); var apiNameToMembers1 = GetApiMemberNamesToMemberDefinitions(winmd1); var apiNameToMembers2 = GetApiMemberNamesToMemberDefinitions(winmd2); HashSet <string> visitedM2Names = new HashSet <string>(); foreach (var api1MemberInfo in apiNameToMembers1) { if (apiNameToMembers2.TryGetValue(api1MemberInfo.Key, out var api2Members)) { foreach (var m1 in api1MemberInfo.Value) { string m1FullName = GetFullMemberName(m1); bool found = false; foreach (var m2 in api2Members) { if (m1.GetType() == m2.GetType()) { string m2FullName = GetFullMemberName(m2); bool membersSame; if (m1 is IField) { membersSame = CompareFields((IField)m1, (IField)m2, console); } else { membersSame = CompareMethods((IMethod)m1, (IMethod)m2, null); // If the members aren't the same on the methods and the namespaces also aren't // the same, then assume these aren't the same methods and keep going if (!membersSame && (m1.Namespace != m2.Namespace)) { continue; } if (!membersSame && console != null) { CompareMethods((IMethod)m1, (IMethod)m2, console); } } if (membersSame) { if (m1.Namespace != m2.Namespace) { console?.Out.Write($"{m1FullName} => {m2FullName}\r\n"); membersSame = false; } } same &= membersSame; visitedM2Names.Add(m2FullName); found = true; break; } } if (!found) { console?.Out.Write($"{m1FullName} not found in 2nd winmd\r\n"); } } } else { foreach (var m1 in api1MemberInfo.Value) { string m1FullName = GetFullMemberName(m1); console?.Out.Write($"{m1FullName} not found in 2nd winmd\r\n"); same = false; } } } foreach (var api2MemberInfo in apiNameToMembers2) { foreach (var api2Member in api2MemberInfo.Value) { string m2FullName = GetFullMemberName(api2Member); if (!visitedM2Names.Contains(m2FullName)) { console?.Out.Write($"{m2FullName} not found in 1st winmd\r\n"); same = false; } } } if (same) { console.Out.Write($"No differences in winmd contents.\r\n"); } return(same ? 0 : -1); }
void Run([CallerMemberName] string testName = null, CompilerOptions options = CompilerOptions.UseDebug, DecompilerSettings settings = null) { var vbFile = Path.Combine(TestCasePath, testName + ".vb"); var csFile = Path.Combine(TestCasePath, testName + ".cs"); var exeFile = Path.Combine(TestCasePath, testName) + Tester.GetSuffix(options) + ".exe"; if (options.HasFlag(CompilerOptions.Library)) { exeFile = Path.ChangeExtension(exeFile, ".dll"); } var executable = Tester.CompileVB(vbFile, options | CompilerOptions.ReferenceVisualBasic, exeFile); var decompiled = Tester.DecompileCSharp(executable.PathToAssembly, settings); CodeAssert.FilesAreEqual(csFile, decompiled); }
public static int ShowDuplicateTypes(FileInfo winmd, IConsole console) { DecompilerSettings settings = new DecompilerSettings() { ThrowOnAssemblyResolveErrors = false }; DecompilerTypeSystem winmd1 = CreateTypeSystemFromFile(winmd.FullName, settings); Dictionary <string, List <string> > nameToNamespaces = new Dictionary <string, List <string> >(); foreach (var type1 in winmd1.GetTopLevelTypeDefinitions()) { if (type1.FullName == "<Module>") { continue; } if (type1.ParentModule != winmd1.MainModule) { continue; } var typeName = type1.Name; if (type1.Kind == TypeKind.Class && typeName == "Apis") { continue; } StringBuilder members = new StringBuilder(); foreach (var m in type1.Members) { if (type1.Kind == TypeKind.Enum && m.Name == "value__") { continue; } if (m.Name == ".ctor") { continue; } if (members.Length != 0) { members.Append(','); } members.Append(m.Name); } if (members.Length != 0) { typeName += $"({members})"; } string archInfo = GetArchInfo(type1.GetAttributes()); if (!string.IsNullOrEmpty(archInfo)) { typeName += $"({archInfo})"; } if (!nameToNamespaces.TryGetValue(typeName, out var namespaces)) { namespaces = new List <string>(); nameToNamespaces[typeName] = namespaces; } namespaces.Add(type1.Namespace); } bool dupsFound = false; foreach (var pair in nameToNamespaces) { if (pair.Value.Count > 1) { if (dupsFound == false) { dupsFound = true; console.Out.Write("Duplicate types detected:\r\n"); } pair.Value.Sort(); console?.Out.Write($"{pair.Key}\r\n"); foreach (var ns in pair.Value) { console?.Out.Write($" {ns}\r\n"); } } } if (!dupsFound) { console.Out.Write("No duplicate types found.\r\n"); } return(dupsFound ? -1 : 0); }
public static List <ReferenceSegment> Decompile(TextEditor data, ModuleDefinition module, TypeDefinition currentType, Action <AstBuilder> setData, DecompilerSettings settings) { var context = new DecompilerContext(module); var source = new CancellationTokenSource(); context.CancellationToken = source.Token; context.CurrentType = currentType; context.Settings = settings; try { var astBuilder = new AstBuilder(context); setData(astBuilder); astBuilder.RunTransformations(o => false); GeneratedCodeSettings.Default.Apply(astBuilder.SyntaxTree); var output = new ColoredCSharpFormatter(data); astBuilder.GenerateCode(output); output.SetDocumentData(); return(output.ReferencedSegments); } catch (Exception e) { // exception -> try to decompile without method bodies try { var astBuilder = new AstBuilder(context); astBuilder.DecompileMethodBodies = false; setData(astBuilder); astBuilder.RunTransformations(o => false); GeneratedCodeSettings.Default.Apply(astBuilder.SyntaxTree); var output = new ColoredCSharpFormatter(data); astBuilder.GenerateCode(output); output.SetDocumentData(); data.InsertText(data.Length, "/* body decompilation failed: \n" + e + " */"); } catch (Exception e2) { data.Text = "/* fallback decompilation failed: \n" + e2 + "*/"; } } return(null); }
public static List <ReferenceSegment> Decompile(TextEditorData data, ModuleDefinition module, TypeDefinition currentType, Action <AstBuilder> setData, DecompilerSettings settings) { try { var context = new DecompilerContext(module); var source = new CancellationTokenSource(); context.CancellationToken = source.Token; context.CurrentType = currentType; context.Settings = settings; AstBuilder astBuilder = new AstBuilder(context); setData(astBuilder); astBuilder.RunTransformations(o => false); GeneratedCodeSettings.Default.Apply(astBuilder.SyntaxTree); var output = new ColoredCSharpFormatter(data.Document); astBuilder.GenerateCode(output); output.SetDocumentData(); return(output.ReferencedSegments); } catch (Exception e) { data.Text = "Decompilation failed: \n" + e; } return(null); }
public void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilerSettings options) { AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: property.DeclaringType, isSingleMember: true); codeDomBuilder.AddProperty(property); RunTransformsAndGenerateCode(codeDomBuilder, output, options); }
void Run([CallerMemberName] string testName = null, AssemblerOptions asmOptions = AssemblerOptions.None, CompilerOptions cscOptions = CompilerOptions.None, DecompilerSettings decompilerSettings = null) { var csFile = Path.Combine(TestCasePath, testName + ".cs"); var exeFile = Path.Combine(TestCasePath, testName) + Tester.GetSuffix(cscOptions) + ".exe"; if (cscOptions.HasFlag(CompilerOptions.Library)) { exeFile = Path.ChangeExtension(exeFile, ".dll"); } // 1. Compile CompilerResults output = null; try { output = Tester.CompileCSharp(csFile, cscOptions, exeFile); } finally { if (output != null) { output.TempFiles.Delete(); } } // 2. Decompile var decompiled = Tester.DecompileCSharp(exeFile, decompilerSettings ?? Tester.GetSettings(cscOptions)); // 3. Compile CodeAssert.FilesAreEqual(csFile, decompiled, Tester.GetPreprocessorSymbols(cscOptions).ToArray()); }
private async Task <List <TestResult> > RunTestOnHardwareAsync(List <TestCase> tests) { _logger.LogMessage( "Setting up test runner in *** CONNECTED DEVICE ***", Settings.LoggingLevel.Detailed); List <TestResult> results = PrepareListResult(tests); List <byte[]> assemblies = new List <byte[]>(); int retryCount = 0; string port = _settings.RealHardwarePort == string.Empty ? "COM4" : _settings.RealHardwarePort; //var serialDebugClient = PortBase.CreateInstanceForSerial("", null, true, new List<string>() { port }); var serialDebugClient = PortBase.CreateInstanceForSerial(true, null); retryConnection: _logger.LogMessage($"Checking device on port {port}.", Settings.LoggingLevel.Verbose); while (!serialDebugClient.IsDevicesEnumerationComplete) { Thread.Sleep(1); } _logger.LogMessage($"Found: {serialDebugClient.NanoFrameworkDevices.Count} devices", Settings.LoggingLevel.Verbose); if (serialDebugClient.NanoFrameworkDevices.Count == 0) { if (retryCount > _numberOfRetries) { results.First().Outcome = TestOutcome.Failed; results.First().ErrorMessage = $"Couldn't find any device, please try to disable the device scanning in the Visual Studio Extension! If the situation persists reboot the device as well."; return(results); } else { retryCount++; serialDebugClient.ReScanDevices(); goto retryConnection; } } retryCount = 0; NanoDeviceBase device; if (serialDebugClient.NanoFrameworkDevices.Count > 1) { device = serialDebugClient.NanoFrameworkDevices.Where(m => m.SerialNumber == port).First(); } else { device = serialDebugClient.NanoFrameworkDevices[0]; } _logger.LogMessage( $"Getting things with {device.Description}", Settings.LoggingLevel.Detailed); // check if debugger engine exists if (device.DebugEngine == null) { device.CreateDebugEngine(); _logger.LogMessage($"Debug engine created.", Settings.LoggingLevel.Verbose); } bool deviceIsInInitializeState = false; retryDebug: bool connectResult = device.DebugEngine.Connect(5000, true, true); _logger.LogMessage($"Device connect result is {connectResult}. Attempt {retryCount}/{_numberOfRetries}", Settings.LoggingLevel.Verbose); if (!connectResult) { if (retryCount < _numberOfRetries) { // Give it a bit of time await Task.Delay(100); retryCount++; goto retryDebug; } else { results.First().Outcome = TestOutcome.Failed; results.First().ErrorMessage = $"Couldn't connect to the device, please try to disable the device scanning in the Visual Studio Extension! If the situation persists reboot the device as well."; return(results); } } retryCount = 0; retryErase: // erase the device _logger.LogMessage($"Erase deployment block storage. Attempt {retryCount}/{_numberOfRetries}.", Settings.LoggingLevel.Verbose); var eraseResult = device.Erase( EraseOptions.Deployment, null, null); _logger.LogMessage($"Erase result is {eraseResult}.", Settings.LoggingLevel.Verbose); if (!eraseResult) { if (retryCount < _numberOfRetries) { // Give it a bit of time await Task.Delay(400); retryCount++; goto retryErase; } else { results.First().Outcome = TestOutcome.Failed; results.First().ErrorMessage = $"Couldn't erase the device, please try to disable the device scanning in the Visual Studio Extension! If the situation persists reboot the device as well."; return(results); } } retryCount = 0; // initial check if (device.DebugEngine.IsDeviceInInitializeState()) { _logger.LogMessage($"Device status verified as being in initialized state. Requesting to resume execution. Attempt {retryCount}/{_numberOfRetries}.", Settings.LoggingLevel.Error); // set flag deviceIsInInitializeState = true; // device is still in initialization state, try resume execution device.DebugEngine.ResumeExecution(); } // handle the workflow required to try resuming the execution on the device // only required if device is not already there // retry 5 times with a 500ms interval between retries while (retryCount++ < _numberOfRetries && deviceIsInInitializeState) { if (!device.DebugEngine.IsDeviceInInitializeState()) { _logger.LogMessage($"Device has completed initialization.", Settings.LoggingLevel.Verbose); // done here deviceIsInInitializeState = false; break; } _logger.LogMessage($"Waiting for device to report initialization completed ({retryCount}/{_numberOfRetries}).", Settings.LoggingLevel.Verbose); // provide feedback to user on the 1st pass if (retryCount == 0) { _logger.LogMessage($"Waiting for device to initialize.", Settings.LoggingLevel.Verbose); } if (device.DebugEngine.IsConnectedTonanoBooter) { _logger.LogMessage($"Device reported running nanoBooter. Requesting to load nanoCLR.", Settings.LoggingLevel.Verbose); // request nanoBooter to load CLR device.DebugEngine.ExecuteMemory(0); } else if (device.DebugEngine.IsConnectedTonanoCLR) { _logger.LogMessage($"Device reported running nanoCLR. Requesting to reboot nanoCLR.", Settings.LoggingLevel.Error); await Task.Run(delegate { // already running nanoCLR try rebooting the CLR device.DebugEngine.RebootDevice(RebootOptions.ClrOnly); }); } // wait before next pass // use a back-off strategy of increasing the wait time to accommodate slower or less responsive targets (such as networked ones) await Task.Delay(TimeSpan.FromMilliseconds(_timeoutMiliseconds * (retryCount + 1))); await Task.Yield(); } // check if device is still in initialized state if (!deviceIsInInitializeState) { // device has left initialization state _logger.LogMessage($"Device is initialized and ready!", Settings.LoggingLevel.Verbose); await Task.Yield(); ////////////////////////////////////////////////////////// // sanity check for devices without native assemblies ?!?! if (device.DeviceInfo.NativeAssemblies.Count == 0) { _logger.LogMessage($"Device reporting no assemblies loaded. This can not happen. Sanity check failed.", Settings.LoggingLevel.Error); // there are no assemblies deployed?! results.First().Outcome = TestOutcome.Failed; results.First().ErrorMessage = $"Couldn't find any native assemblies deployed in {device.Description}, {device.TargetName} on {device.SerialNumber}! If the situation persists reboot the device."; return(results); } _logger.LogMessage($"Computing deployment blob.", Settings.LoggingLevel.Verbose); // build a list with the full path for each DLL, referenced DLL and EXE List <DeploymentAssembly> assemblyList = new List <DeploymentAssembly>(); var source = tests.First().Source; var workingDirectory = Path.GetDirectoryName(source); var allPeFiles = Directory.GetFiles(workingDirectory, "*.pe"); var decompilerSettings = new DecompilerSettings { LoadInMemory = false, ThrowOnAssemblyResolveErrors = false }; foreach (string assemblyPath in allPeFiles) { // load assembly in order to get the versions var file = Path.Combine(workingDirectory, assemblyPath.Replace(".pe", ".dll")); if (!File.Exists(file)) { // Check with an exe file = Path.Combine(workingDirectory, assemblyPath.Replace(".pe", ".exe")); } var decompiler = new CSharpDecompiler(file, decompilerSettings);; var assemblyProperties = decompiler.DecompileModuleAndAssemblyAttributesToString(); // AssemblyVersion string pattern = @"(?<=AssemblyVersion\("")(.*)(?=\""\)])"; var match = Regex.Matches(assemblyProperties, pattern, RegexOptions.IgnoreCase); string assemblyVersion = match[0].Value; // AssemblyNativeVersion pattern = @"(?<=AssemblyNativeVersion\("")(.*)(?=\""\)])"; match = Regex.Matches(assemblyProperties, pattern, RegexOptions.IgnoreCase); // only class libs have this attribute, therefore sanity check is required string nativeVersion = ""; if (match.Count == 1) { nativeVersion = match[0].Value; } assemblyList.Add(new DeploymentAssembly(Path.Combine(workingDirectory, assemblyPath), assemblyVersion, nativeVersion)); } _logger.LogMessage($"Added {assemblyList.Count} assemblies to deploy.", Settings.LoggingLevel.Verbose); await Task.Yield(); // Keep track of total assembly size long totalSizeOfAssemblies = 0; // now we will re-deploy all system assemblies foreach (DeploymentAssembly peItem in assemblyList) { // append to the deploy blob the assembly using (FileStream fs = File.Open(peItem.Path, FileMode.Open, FileAccess.Read)) { long length = (fs.Length + 3) / 4 * 4; _logger.LogMessage($"Adding {Path.GetFileNameWithoutExtension(peItem.Path)} v{peItem.Version} ({length} bytes) to deployment bundle", Settings.LoggingLevel.Verbose); byte[] buffer = new byte[length]; await Task.Yield(); await fs.ReadAsync(buffer, 0, (int)fs.Length); assemblies.Add(buffer); // Increment totalizer totalSizeOfAssemblies += length; } } _logger.LogMessage($"Deploying {assemblyList.Count:N0} assemblies to device... Total size in bytes is {totalSizeOfAssemblies}.", Settings.LoggingLevel.Verbose); // need to keep a copy of the deployment blob for the second attempt (if needed) var assemblyCopy = new List <byte[]>(assemblies); await Task.Yield(); var deploymentLogger = new Progress <string>((m) => _logger.LogMessage(m, Settings.LoggingLevel.Detailed)); await Task.Run(async delegate { // OK to skip erase as we just did that // no need to reboot device if (!device.DebugEngine.DeploymentExecute( assemblyCopy, false, false, null, deploymentLogger)) { // if the first attempt fails, give it another try // wait before next pass await Task.Delay(TimeSpan.FromSeconds(1)); await Task.Yield(); _logger.LogMessage("Deploying assemblies. Second attempt.", Settings.LoggingLevel.Verbose); // !! need to use the deployment blob copy assemblyCopy = new List <byte[]>(assemblies); // can't skip erase as we just did that // no need to reboot device if (!device.DebugEngine.DeploymentExecute( assemblyCopy, false, false, null, deploymentLogger)) { _logger.LogMessage("Deployment failed.", Settings.LoggingLevel.Error); // throw exception to signal deployment failure results.First().Outcome = TestOutcome.Failed; results.First().ErrorMessage = $"Deployment failed in {device.Description}, {device.TargetName} on {device.SerialNumber}! If the situation persists reboot the device."; } } }); await Task.Yield(); // If there has been an issue before, the first test is marked as failed if (results.First().Outcome == TestOutcome.Failed) { return(results); } StringBuilder output = new StringBuilder(); bool isFinished = false; // attach listener for messages device.DebugEngine.OnMessage += (message, text) => { _logger.LogMessage(text, Settings.LoggingLevel.Verbose); output.Append(text); if (text.Contains(Done)) { isFinished = true; } }; device.DebugEngine.RebootDevice(RebootOptions.ClrOnly); while (!isFinished) { Thread.Sleep(1); } _logger.LogMessage($"Tests finished.", Settings.LoggingLevel.Verbose); CheckAllTests(output.ToString(), results); } else { _logger.LogMessage("Failed to initialize device.", Settings.LoggingLevel.Error); } return(results); }
internal static DecompilerSettings CreateDecompilerSettings_DecompileTypeMethods(DecompilerSettings settings, bool useUsingDeclarations) { var s = CreateDecompilerSettings(settings, useUsingDeclarations); // Make sure the ctor is shown if the user tries to edit an empty ctor/cctor s.RemoveEmptyDefaultConstructors = false; return(s); }
static bool ValidateCompoundAssign(BinaryNumericInstruction binary, Conv conv, IType targetType, DecompilerSettings settings) { if (!NumericCompoundAssign.IsBinaryCompatibleWithType(binary, targetType, settings)) { return(false); } if (conv != null && !(conv.TargetType == targetType.ToPrimitiveType() && conv.CheckForOverflow == binary.CheckForOverflow)) { return(false); // conv does not match binary operation } return(true); }
void Run([CallerMemberName] string testName = null, AssemblerOptions asmOptions = AssemblerOptions.None, CompilerOptions cscOptions = CompilerOptions.None, DecompilerSettings decompilerSettings = null) { var ilFile = Path.Combine(TestCasePath, testName) + Tester.GetSuffix(cscOptions) + ".il"; var csFile = Path.Combine(TestCasePath, testName + ".cs"); var expectedFile = Path.Combine(TestCasePath, testName + ".Expected.cs"); if (!File.Exists(ilFile)) { // re-create .il file if necessary CompilerResults output = null; try { output = Tester.CompileCSharp(csFile, cscOptions); Tester.Disassemble(output.PathToAssembly, ilFile, asmOptions); } finally { if (output != null) { output.TempFiles.Delete(); } } } var executable = Tester.AssembleIL(ilFile, asmOptions); var decompiled = Tester.DecompileCSharp(executable, decompilerSettings); CodeAssert.FilesAreEqual(expectedFile, decompiled, Tester.GetPreprocessorSymbols(cscOptions).ToArray()); }
public DecompilerTypeSystem(PEFile mainModule, IAssemblyResolver assemblyResolver, DecompilerSettings settings) : this(mainModule, assemblyResolver, GetOptions(settings ?? throw new ArgumentNullException(nameof(settings))))