Browse Source

Merge branch 'master' of git://github.com/icsharpcode/ILSpy into Debugger

pull/191/merge
Eusebiu Marcu 15 years ago
parent
commit
97b29ce166
  1. 68
      ILSpy/BamlDecompiler.cs
  2. 23
      ILSpy/CSharpLanguage.cs
  3. 2
      ILSpy/Commands.cs
  4. 197
      ILSpy/ConnectMethodDecompiler.cs
  5. 6
      ILSpy/ILLanguage.cs
  6. 3
      ILSpy/ILSpy.csproj
  7. 6
      ILSpy/Language.cs
  8. 2
      ILSpy/TreeNodes/AssemblyTreeNode.cs

68
ILSpy/BamlDecompiler.cs

@ -9,6 +9,7 @@ using System.Reflection; @@ -9,6 +9,7 @@ using System.Reflection;
using System.Threading.Tasks;
using System.Windows.Baml2006;
using System.Xaml;
using System.Xaml.Schema;
using System.Xml;
using System.Xml.Linq;
using ICSharpCode.AvalonEdit.Highlighting;
@ -37,7 +38,7 @@ namespace ICSharpCode.ILSpy.Baml @@ -37,7 +38,7 @@ namespace ICSharpCode.ILSpy.Baml
[Conditional("DEBUG")]
static void Log(string format, params object[] args)
{
//Debug.WriteLine(format, args);
Debug.WriteLine(format, args);
}
sealed class XamlObjectNode : XamlNode
@ -241,8 +242,23 @@ namespace ICSharpCode.ILSpy.Baml @@ -241,8 +242,23 @@ namespace ICSharpCode.ILSpy.Baml
}
}
public string DecompileBaml(MemoryStream bamlCode, string containingAssemblyFile)
AssemblyResolver asmResolver;
Assembly AssemblyResolve(object sender, ResolveEventArgs args)
{
string path = asmResolver.FindAssembly(args.Name);
if (path == null)
return null;
return Assembly.LoadFile(path);
}
public string DecompileBaml(MemoryStream bamlCode, string containingAssemblyFile, ConnectMethodDecompiler connectMethodDecompiler, AssemblyResolver asmResolver)
{
this.asmResolver = asmResolver;
AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolve;
bamlCode.Position = 0;
TextWriter w = new StringWriter();
@ -250,8 +266,13 @@ namespace ICSharpCode.ILSpy.Baml @@ -250,8 +266,13 @@ namespace ICSharpCode.ILSpy.Baml
Baml2006Reader reader = new Baml2006Reader(bamlCode, new XamlReaderSettings() { ValuesMustBeString = true, LocalAssembly = assembly });
var xamlDocument = Parse(reader);
string bamlTypeName = xamlDocument.OfType<XamlObjectNode>().First().Type.UnderlyingType.FullName;
var eventMappings = connectMethodDecompiler.DecompileEventMappings(bamlTypeName);
foreach (var xamlNode in xamlDocument) {
RemoveConnectionIds(xamlNode, eventMappings, reader.SchemaContext);
AvoidContentProperties(xamlNode);
MoveXKeyToFront(xamlNode);
}
@ -277,6 +298,43 @@ namespace ICSharpCode.ILSpy.Baml @@ -277,6 +298,43 @@ namespace ICSharpCode.ILSpy.Baml
return doc.ToString();
}
void RemoveConnectionIds(XamlNode node, Dictionary<int, EventRegistration[]> eventMappings, XamlSchemaContext context)
{
foreach (XamlNode child in node.Children)
RemoveConnectionIds(child, eventMappings, context);
XamlObjectNode obj = node as XamlObjectNode;
if (obj != null && obj.Children.Count > 0) {
var removableNodes = new List<XamlMemberNode>();
var addableNodes = new List<XamlMemberNode>();
foreach (XamlMemberNode memberNode in obj.Children.OfType<XamlMemberNode>()) {
if (memberNode.Member == XamlLanguage.ConnectionId && memberNode.Children.Single() is XamlValueNode) {
var value = memberNode.Children.Single() as XamlValueNode;
int id;
if (value.Value is string && int.TryParse(value.Value as string, out id) && eventMappings.ContainsKey(id)) {
var map = eventMappings[id];
foreach (var entry in map) {
if (entry.IsAttached) {
var type = context.GetXamlType(Type.GetType(entry.AttachSourceType));
var member = new XamlMemberNode(new XamlMember(entry.EventName, type, true));
member.Children.Add(new XamlValueNode(entry.MethodName));
addableNodes.Add(member);
} else {
var member = new XamlMemberNode(obj.Type.GetMember(entry.EventName));
member.Children.Add(new XamlValueNode(entry.MethodName));
addableNodes.Add(member);
}
}
removableNodes.Add(memberNode);
}
}
}
foreach (var rnode in removableNodes)
node.Children.Remove(rnode);
node.Children.InsertRange(node.Children.Count > 1 ? node.Children.Count - 1 : 0, addableNodes);
}
}
/// <summary>
/// Changes all references from oldNamespace to newNamespace in the document.
/// </summary>
@ -345,7 +403,7 @@ namespace ICSharpCode.ILSpy.Baml @@ -345,7 +403,7 @@ namespace ICSharpCode.ILSpy.Baml
data.Position = 0;
data.CopyTo(bamlStream);
output.Write(decompiler.DecompileBaml(bamlStream, asm.FileName));
output.Write(decompiler.DecompileBaml(bamlStream, asm.FileName, new ConnectMethodDecompiler(asm), new AssemblyResolver(asm)));
return true;
} finally {
if (bamlDecompilerAppDomain != null)
@ -358,7 +416,7 @@ namespace ICSharpCode.ILSpy.Baml @@ -358,7 +416,7 @@ namespace ICSharpCode.ILSpy.Baml
if (appDomain == null) {
// Construct and initialize settings for a second AppDomain.
AppDomainSetup bamlDecompilerAppDomainSetup = new AppDomainSetup();
bamlDecompilerAppDomainSetup.ApplicationBase = "file:///" + Path.GetDirectoryName(assemblyFileName);
// bamlDecompilerAppDomainSetup.ApplicationBase = "file:///" + Path.GetDirectoryName(assemblyFileName);
bamlDecompilerAppDomainSetup.DisallowBindingRedirects = false;
bamlDecompilerAppDomainSetup.DisallowCodeDownload = true;
bamlDecompilerAppDomainSetup.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
@ -366,7 +424,7 @@ namespace ICSharpCode.ILSpy.Baml @@ -366,7 +424,7 @@ namespace ICSharpCode.ILSpy.Baml
// Create the second AppDomain.
appDomain = AppDomain.CreateDomain("BamlDecompiler AD", null, bamlDecompilerAppDomainSetup);
}
return (BamlDecompiler)appDomain.CreateInstanceFromAndUnwrap(typeof(BamlDecompiler).Assembly.Location, typeof(BamlDecompiler).FullName);
return (BamlDecompiler)appDomain.CreateInstanceAndUnwrap(typeof(BamlDecompiler).Assembly.FullName, typeof(BamlDecompiler).FullName);
}
}
}

23
ILSpy/CSharpLanguage.cs

@ -32,6 +32,7 @@ using System.Xml; @@ -32,6 +32,7 @@ using System.Xml;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Ast;
using ICSharpCode.Decompiler.Ast.Transforms;
using ICSharpCode.ILSpy.Baml;
using ICSharpCode.ILSpy.Debugger;
using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil;
@ -134,19 +135,19 @@ namespace ICSharpCode.ILSpy @@ -134,19 +135,19 @@ namespace ICSharpCode.ILSpy
OnDecompilationFinished(new DecompileEventArgs { CodeMappings = codeDomBuilder.CodeMappings, LocalVariables = codeDomBuilder.LocalVariables, DecompiledMemberReferences = codeDomBuilder.DecompiledMemberReferences });
}
public override void DecompileAssembly(AssemblyDefinition assembly, string fileName, ITextOutput output, DecompilationOptions options)
public override void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)
{
if (options.FullDecompilation && options.SaveAsProjectDirectory != null) {
HashSet<string> directories = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
var files = WriteCodeFilesInProject(assembly, options, directories).ToList();
files.AddRange(WriteResourceFilesInProject(assembly, fileName, options, directories));
WriteProjectFile(new TextOutputWriter(output), files, assembly.MainModule);
var files = WriteCodeFilesInProject(assembly.AssemblyDefinition, options, directories).ToList();
files.AddRange(WriteResourceFilesInProject(assembly, options, directories));
WriteProjectFile(new TextOutputWriter(output), files, assembly.AssemblyDefinition.MainModule);
} else {
base.DecompileAssembly(assembly, fileName, output, options);
base.DecompileAssembly(assembly, output, options);
// don't automatically load additional assemblies when an assembly node is selected in the tree view
using (options.FullDecompilation ? null : LoadedAssembly.DisableAssemblyLoad()) {
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentModule: assembly.MainModule);
codeDomBuilder.AddAssembly(assembly, onlyAssemblyLevel: !options.FullDecompilation);
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentModule: assembly.AssemblyDefinition.MainModule);
codeDomBuilder.AddAssembly(assembly.AssemblyDefinition, onlyAssemblyLevel: !options.FullDecompilation);
codeDomBuilder.RunTransformations(transformAbortCondition);
codeDomBuilder.GenerateCode(output);
}
@ -324,11 +325,11 @@ namespace ICSharpCode.ILSpy @@ -324,11 +325,11 @@ namespace ICSharpCode.ILSpy
#endregion
#region WriteResourceFilesInProject
IEnumerable<Tuple<string, string>> WriteResourceFilesInProject(AssemblyDefinition assembly, string assemblyFileName, DecompilationOptions options, HashSet<string> directories)
IEnumerable<Tuple<string, string>> WriteResourceFilesInProject(LoadedAssembly assembly, DecompilationOptions options, HashSet<string> directories)
{
AppDomain bamlDecompilerAppDomain = null;
try {
foreach (EmbeddedResource r in assembly.MainModule.Resources.OfType<EmbeddedResource>()) {
foreach (EmbeddedResource r in assembly.AssemblyDefinition.MainModule.Resources.OfType<EmbeddedResource>()) {
string fileName;
Stream s = r.GetResourceStream();
s.Position = 0;
@ -350,10 +351,10 @@ namespace ICSharpCode.ILSpy @@ -350,10 +351,10 @@ namespace ICSharpCode.ILSpy
if (fileName.EndsWith(".baml", StringComparison.OrdinalIgnoreCase)) {
MemoryStream ms = new MemoryStream();
entryStream.CopyTo(ms);
var decompiler = Baml.BamlResourceEntryNode.CreateBamlDecompilerInAppDomain(ref bamlDecompilerAppDomain, assemblyFileName);
var decompiler = Baml.BamlResourceEntryNode.CreateBamlDecompilerInAppDomain(ref bamlDecompilerAppDomain, assembly.FileName);
string xaml = null;
try {
xaml = decompiler.DecompileBaml(ms, assemblyFileName);
xaml = decompiler.DecompileBaml(ms, assembly.FileName, new ConnectMethodDecompiler(assembly), new AssemblyResolver(assembly));
} catch (XamlXmlWriterException) {} // ignore XAML writer exceptions
if (xaml != null) {
File.WriteAllText(Path.Combine(options.SaveAsProjectDirectory, Path.ChangeExtension(fileName, ".xaml")), xaml);

2
ILSpy/Commands.cs

@ -87,7 +87,7 @@ namespace ICSharpCode.ILSpy @@ -87,7 +87,7 @@ namespace ICSharpCode.ILSpy
using (var writer = new System.IO.StreamWriter("c:\\temp\\decompiled\\" + asm.ShortName + ".cs")) {
try {
new CSharpLanguage().DecompileAssembly(
asm.AssemblyDefinition, asm.FileName, new Decompiler.PlainTextOutput(writer),
asm, new Decompiler.PlainTextOutput(writer),
new DecompilationOptions { FullDecompilation = true, CancellationToken = ct });
} catch (Exception ex) {
writer.WriteLine(ex.ToString());

197
ILSpy/ConnectMethodDecompiler.cs

@ -0,0 +1,197 @@ @@ -0,0 +1,197 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.ILAst;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace ICSharpCode.ILSpy.Baml
{
[Serializable]
sealed class EventRegistration
{
public string EventName, MethodName, AttachSourceType;
public bool IsAttached;
}
/// <summary>
/// Description of ConnectMethodDecompiler.
/// </summary>
sealed class ConnectMethodDecompiler : MarshalByRefObject
{
LoadedAssembly assembly;
public ConnectMethodDecompiler(LoadedAssembly assembly)
{
this.assembly = assembly;
}
public Dictionary<int, EventRegistration[]> DecompileEventMappings(string fullTypeName)
{
var result = new Dictionary<int, EventRegistration[]>();
TypeDefinition type = this.assembly.AssemblyDefinition.MainModule.GetType(fullTypeName);
if (type == null)
return result;
MethodDefinition def = null;
foreach (var method in type.Methods) {
if (method.Name == "System.Windows.Markup.IComponentConnector.Connect") {
def = method;
break;
}
}
if (def == null)
return result;
// decompile method and optimize the switch
ILBlock ilMethod = new ILBlock();
ILAstBuilder astBuilder = new ILAstBuilder();
ilMethod.Body = astBuilder.Build(def, true);
ILAstOptimizer optimizer = new ILAstOptimizer();
var context = new DecompilerContext(type.Module) { CurrentMethod = def, CurrentType = type };
optimizer.Optimize(context, ilMethod, ILAstOptimizationStep.RemoveRedundantCode3);
ILSwitch ilSwitch = ilMethod.Body.OfType<ILSwitch>().FirstOrDefault();
ILCondition condition = ilMethod.Body.OfType<ILCondition>().FirstOrDefault();
if (ilSwitch != null) {
foreach (var caseBlock in ilSwitch.CaseBlocks) {
if (caseBlock.Values == null)
continue;
var events = FindEvents(caseBlock);
foreach (int id in caseBlock.Values)
result.Add(id, events);
}
} else if (condition != null) {
result.Add(1, FindEvents(condition.FalseBlock));
}
return result;
}
EventRegistration[] FindEvents(ILBlock block)
{
var events = new List<EventRegistration>();
foreach (var node in block.Body) {
var expr = node as ILExpression;
string eventName, handlerName, attachSource;
if (IsAddEvent(expr, out eventName, out handlerName))
events.Add(new EventRegistration {
EventName = eventName,
MethodName = handlerName
});
else if (IsAddAttachedEvent(expr, out eventName, out handlerName, out attachSource))
events.Add(new EventRegistration {
EventName = eventName,
MethodName = handlerName,
AttachSourceType = attachSource,
IsAttached = true
});
}
return events.ToArray();
}
bool IsAddAttachedEvent(ILExpression expr, out string eventName, out string handlerName, out string attachSource)
{
eventName = "";
handlerName = "";
attachSource = "";
if (expr == null || !(expr.Code == ILCode.Callvirt || expr.Code == ILCode.Call))
return false;
if (expr.Operand is MethodReference && expr.Arguments.Count == 3) {
var addMethod = expr.Operand as MethodReference;
if (addMethod.Name != "AddHandler" || addMethod.Parameters.Count != 2)
return false;
var arg = expr.Arguments[1];
if (arg.Code != ILCode.Ldsfld || arg.Arguments.Any() || !(arg.Operand is FieldReference))
return false;
FieldReference fldRef = (FieldReference)arg.Operand;
attachSource = GetAssemblyQualifiedName(fldRef.DeclaringType);
eventName = fldRef.Name;
if (eventName.EndsWith("Event") && eventName.Length > "Event".Length)
eventName = eventName.Remove(eventName.Length - "Event".Length);
var arg1 = expr.Arguments[2];
if (arg1.Code != ILCode.Newobj)
return false;
var arg2 = arg1.Arguments[1];
if (arg2.Code != ILCode.Ldftn && arg2.Code != ILCode.Ldvirtftn)
return false;
if (arg2.Operand is MethodReference) {
var m = arg2.Operand as MethodReference;
handlerName = m.Name;
return true;
}
}
return false;
}
string GetAssemblyQualifiedName(TypeReference declaringType)
{
string fullName = declaringType.FullName;
if (declaringType.Scope is AssemblyNameReference)
fullName += ", " + ((AssemblyNameReference)declaringType.Scope).FullName;
else if (declaringType.Scope is ModuleDefinition)
fullName += ", " + ((ModuleDefinition)declaringType.Scope).Assembly.FullName;
return fullName;
}
bool IsAddEvent(ILExpression expr, out string eventName, out string handlerName)
{
eventName = "";
handlerName = "";
if (expr == null || !(expr.Code == ILCode.Callvirt || expr.Code == ILCode.Call))
return false;
if (expr.Operand is MethodReference && expr.Arguments.Count == 2) {
var addMethod = expr.Operand as MethodReference;
if (addMethod.Name.StartsWith("add_") && addMethod.Parameters.Count == 1)
eventName = addMethod.Name.Substring("add_".Length);
var arg = expr.Arguments[1];
if (arg.Code != ILCode.Newobj || arg.Arguments.Count != 2)
return false;
var arg1 = arg.Arguments[1];
if (arg1.Code != ILCode.Ldftn && arg1.Code != ILCode.Ldvirtftn)
return false;
if (arg1.Operand is MethodReference) {
var m = arg1.Operand as MethodReference;
handlerName = m.Name;
return true;
}
}
return false;
}
}
sealed class AssemblyResolver : MarshalByRefObject
{
LoadedAssembly assembly;
public AssemblyResolver(LoadedAssembly assembly)
{
this.assembly = assembly;
}
public string FindAssembly(string name)
{
var asm = assembly.LookupReferencedAssembly(name);
return asm == null ? null : asm.FileName;
}
}
}

6
ILSpy/ILLanguage.cs

@ -92,12 +92,12 @@ namespace ICSharpCode.ILSpy @@ -92,12 +92,12 @@ namespace ICSharpCode.ILSpy
OnDecompilationFinished(null);
}
public override void DecompileAssembly(AssemblyDefinition assembly, string fileName, ITextOutput output, DecompilationOptions options)
public override void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)
{
output.WriteLine("// " + fileName);
output.WriteLine("// " + assembly.FileName);
output.WriteLine();
new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken).WriteAssemblyHeader(assembly);
new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken).WriteAssemblyHeader(assembly.AssemblyDefinition);
OnDecompilationFinished(null);
}

3
ILSpy/ILSpy.csproj

@ -94,12 +94,13 @@ @@ -94,12 +94,13 @@
<Compile Include="BamlDecompiler.cs" />
<Compile Include="CommandLineArguments.cs" />
<Compile Include="Commands.cs" />
<Compile Include="ConnectMethodDecompiler.cs" />
<Compile Include="ExportCommandAttribute.cs" />
<Compile Include="Commands\DebuggerCommands.cs" />
<Compile Include="Controls\SearchBox.cs" />
<Compile Include="Controls\SortableGridViewColumn.cs" />
<Compile Include="CSharpLanguage.cs" />
<Compile Include="DecompilationOptions.cs" />
<Compile Include="ExportCommandAttribute.cs" />
<Compile Include="ExtensionMethods.cs" />
<Compile Include="FilterSettings.cs" />
<Compile Include="Fusion.cs" />

6
ILSpy/Language.cs

@ -113,10 +113,10 @@ namespace ICSharpCode.ILSpy @@ -113,10 +113,10 @@ namespace ICSharpCode.ILSpy
WriteCommentLine(output, nameSpace);
}
public virtual void DecompileAssembly(AssemblyDefinition assembly, string fileName, ITextOutput output, DecompilationOptions options)
public virtual void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)
{
WriteCommentLine(output, fileName);
WriteCommentLine(output, assembly.Name.FullName);
WriteCommentLine(output, assembly.FileName);
WriteCommentLine(output, assembly.AssemblyDefinition.FullName);
}
public virtual void WriteCommentLine(ITextOutput output, string comment)

2
ILSpy/TreeNodes/AssemblyTreeNode.cs

@ -186,7 +186,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -186,7 +186,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
assembly.WaitUntilLoaded(); // necessary so that load errors are passed on to the caller
language.DecompileAssembly(assembly.AssemblyDefinition, assembly.FileName, output, options);
language.DecompileAssembly(assembly, output, options);
}
public override bool Save(DecompilerTextView textView)

Loading…
Cancel
Save