Skip to content

Commit

Permalink
Merge branch 'master' of git://github.com/icsharpcode/ILSpy into Debu…
Browse files Browse the repository at this point in the history
…gger
  • Loading branch information
eusebiu committed Feb 23, 2011
2 parents 951acde + 7f1a946 commit 0c2a2ab
Show file tree
Hide file tree
Showing 11 changed files with 253 additions and 60 deletions.
2 changes: 1 addition & 1 deletion ICSharpCode.Decompiler/Disassembler/ILStructure.cs
Expand Up @@ -92,7 +92,7 @@ public ILStructure(MethodBody body)
AddNestedStructure(new ILStructure(ILStructureType.Try, eh.TryStart.Offset, eh.TryEnd.Offset, eh));
if (eh.HandlerType == ExceptionHandlerType.Filter)
AddNestedStructure(new ILStructure(ILStructureType.Filter, eh.FilterStart.Offset, eh.FilterEnd.Offset, eh));
AddNestedStructure(new ILStructure(ILStructureType.Handler, eh.HandlerStart.Offset, eh.HandlerEnd.Offset, eh));
AddNestedStructure(new ILStructure(ILStructureType.Handler, eh.HandlerStart.Offset, eh.HandlerEnd == null ? body.CodeSize : eh.HandlerEnd.Offset, eh));
}
// Very simple loop detection: look for backward branches
List<KeyValuePair<Instruction, Instruction>> allBranches = FindAllBranches(body);
Expand Down
5 changes: 3 additions & 2 deletions ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs
Expand Up @@ -567,8 +567,9 @@ List<ILNode> ConvertToAst(List<ByteCode> body, HashSet<ExceptionHandler> ehs)
int startIndex;
for (startIndex = 0; body[startIndex].Offset != eh.HandlerStart.Offset; startIndex++);
int endInclusiveIndex;
// Note that the end(exclusiove) instruction may not necessarly be in our body
for (endInclusiveIndex = 0; body[endInclusiveIndex].Next.Offset != eh.HandlerEnd.Offset; endInclusiveIndex++);
if (eh.HandlerEnd == null) endInclusiveIndex = body.Count - 1;
// Note that the end(exclusive) instruction may not necessarly be in our body
else for (endInclusiveIndex = 0; body[endInclusiveIndex].Next.Offset != eh.HandlerEnd.Offset; endInclusiveIndex++);
int count = 1 + endInclusiveIndex - startIndex;
HashSet<ExceptionHandler> nestedEHs = new HashSet<ExceptionHandler>(ehs.Where(e => (eh.HandlerStart.Offset <= e.TryStart.Offset && e.TryEnd.Offset < eh.HandlerEnd.Offset) || (eh.HandlerStart.Offset < e.TryStart.Offset && e.TryEnd.Offset <= eh.HandlerEnd.Offset)));
ehs.ExceptWith(nestedEHs);
Expand Down
6 changes: 4 additions & 2 deletions ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
Expand Up @@ -286,7 +286,9 @@ TypeReference DoInferTypeForExpression(ILExpression expr, TypeReference expected
case ILCode.Ldvirtftn:
return typeSystem.IntPtr;
case ILCode.Ldc_I4:
return (IsIntegerOrEnum(expectedType) || IsBoolean(expectedType)) ? expectedType : typeSystem.Int32;
if (IsBoolean(expectedType) && ((int)expr.Operand == 0 || (int)expr.Operand == 1))
return typeSystem.Boolean;
return IsIntegerOrEnum(expectedType) ? expectedType : typeSystem.Int32;
case ILCode.Ldc_I8:
return (IsIntegerOrEnum(expectedType)) ? expectedType : typeSystem.Int64;
case ILCode.Ldc_R4:
Expand Down Expand Up @@ -561,7 +563,7 @@ TypeReference InferArgumentsInBinaryOperator(ILExpression expr, bool? isSigned)
} else {
left.ExpectedType = right.ExpectedType = TypeWithMoreInformation(leftPreferred, rightPreferred);
left.InferredType = DoInferTypeForExpression(left, left.ExpectedType);
right.InferredType = DoInferTypeForExpression(left, right.ExpectedType);
right.InferredType = DoInferTypeForExpression(right, right.ExpectedType);
return left.ExpectedType;
}
}
Expand Down
59 changes: 59 additions & 0 deletions ICSharpCode.Decompiler/Tests/BooleanConsumedAsInteger.il
@@ -0,0 +1,59 @@
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 )
.ver 4:0:0:0
}
.assembly BooleanConsumedAsInteger
{
.hash algorithm 0x00008004
.ver 1:0:0:0
}
.module BooleanConsumedAsInteger.exe
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000003 // ILONLY 32BITREQUIRED

.class private auto ansi beforefieldinit BooleanConsumedAsInteger.Program extends [mscorlib]System.Object
{
.method public hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 8

ret
}

.method public hidebysig static int32 ReturnBoolAsInt() cil managed
{
ldnull
ldnull
call bool [mscorlib] System.Object::Equals(object, object)
ret
}

.method public hidebysig static int32 BitwiseOperationOnBool() cil managed
{
ldnull
ldnull
call bool [mscorlib] System.Object::Equals(object, object)
ldc.i4 255
and
ret
}

.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method Program::.ctor

} // end of class StackTests.Program


// =============================================================
25 changes: 25 additions & 0 deletions ICSharpCode.Decompiler/Tests/ExceptionHandling.cs
@@ -0,0 +1,25 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)

using System;

public class ExceptionHandling
{
public void MethodEndingWithEndFinally()
{
try {
throw null;
} finally {
Console.WriteLine();
}
}

public void MethodEndingWithRethrow()
{
try {
throw null;
} catch {
throw;
}
}
}
Expand Up @@ -49,6 +49,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="DelegateConstruction.cs" />
<Compile Include="ExceptionHandling.cs" />
<Compile Include="Loops.cs" />
<Compile Include="PropertiesAndEvents.cs" />
<Compile Include="TestRunner.cs" />
Expand All @@ -64,5 +65,12 @@
<Name>ICSharpCode.Decompiler</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Folder Include="StackTests" />
</ItemGroup>
<ItemGroup>
<None Include="BooleanConsumedAsInteger.il" />
<None Include="StackTests\StackTests.il" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
</Project>
109 changes: 97 additions & 12 deletions ILSpy/CSharpLanguage.cs
Expand Up @@ -17,12 +17,15 @@
// DEALINGS IN THE SOFTWARE.

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Resources;
using System.Threading.Tasks;
using System.Xaml;
using System.Xml;

using Decompiler;
using Decompiler.Transforms;
using ICSharpCode.Decompiler;
Expand Down Expand Up @@ -115,7 +118,9 @@ public override void DecompileAssembly(AssemblyDefinition assembly, string fileN
{
if (options.FullDecompilation) {
if (options.SaveAsProjectDirectory != null) {
var files = WriteFilesInProject(assembly, options);
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);
} else {
foreach (TypeDefinition type in assembly.MainModule.Types) {
Expand All @@ -130,7 +135,8 @@ public override void DecompileAssembly(AssemblyDefinition assembly, string fileN
}
}

void WriteProjectFile(TextWriter writer, IEnumerable<string> files, ModuleDefinition module)
#region WriteProjectFile
void WriteProjectFile(TextWriter writer, IEnumerable<Tuple<string, string>> files, ModuleDefinition module)
{
const string ns = "http://schemas.microsoft.com/developer/msbuild/2003";
string platformName;
Expand Down Expand Up @@ -236,13 +242,15 @@ void WriteProjectFile(TextWriter writer, IEnumerable<string> files, ModuleDefini
}
w.WriteEndElement(); // </ItemGroup> (References)

w.WriteStartElement("ItemGroup"); // Code
foreach (string file in files.OrderBy(f => f, StringComparer.OrdinalIgnoreCase)) {
w.WriteStartElement("Compile");
w.WriteAttributeString("Include", file);
foreach (IGrouping<string, string> gr in (from f in files group f.Item2 by f.Item1 into g orderby g.Key select g)) {
w.WriteStartElement("ItemGroup");
foreach (string file in gr.OrderBy(f => f, StringComparer.OrdinalIgnoreCase)) {
w.WriteStartElement(gr.Key);
w.WriteAttributeString("Include", file);
w.WriteEndElement();
}
w.WriteEndElement();
}
w.WriteEndElement();

w.WriteStartElement("Import");
w.WriteAttributeString("Project", "$(MSBuildToolsPath)\\Microsoft.CSharp.targets");
Expand All @@ -251,8 +259,10 @@ void WriteProjectFile(TextWriter writer, IEnumerable<string> files, ModuleDefini
w.WriteEndDocument();
}
}
#endregion

IEnumerable<string> WriteFilesInProject(AssemblyDefinition assembly, DecompilationOptions options)
#region WriteCodeFilesInProject
IEnumerable<Tuple<string, string>> WriteCodeFilesInProject(AssemblyDefinition assembly, DecompilationOptions options, HashSet<string> directories)
{
var files = assembly.MainModule.Types.Where(t => t.Name != "<Module>").GroupBy(
delegate (TypeDefinition type) {
Expand All @@ -261,11 +271,11 @@ IEnumerable<string> WriteFilesInProject(AssemblyDefinition assembly, Decompilati
return file;
} else {
string dir = TextView.DecompilerTextView.CleanUpName(type.Namespace);
Directory.CreateDirectory(Path.Combine(options.SaveAsProjectDirectory, dir));
if (directories.Add(dir))
Directory.CreateDirectory(Path.Combine(options.SaveAsProjectDirectory, dir));
return Path.Combine(dir, file);
}
}, StringComparer.OrdinalIgnoreCase).ToList();

AstMethodBodyBuilder.ClearUnhandledOpcodes();
Parallel.ForEach(
files,
Expand All @@ -279,8 +289,83 @@ IEnumerable<string> WriteFilesInProject(AssemblyDefinition assembly, Decompilati
}
});
AstMethodBodyBuilder.PrintNumberOfUnhandledOpcodes();
return files.Select(f => f.Key);
return files.Select(f => Tuple.Create("Compile", f.Key));
}
#endregion

#region WriteResourceFilesInProject
IEnumerable<Tuple<string, string>> WriteResourceFilesInProject(AssemblyDefinition assembly, string assemblyFileName, DecompilationOptions options, HashSet<string> directories)
{
AppDomain bamlDecompilerAppDomain = null;
try {
foreach (EmbeddedResource r in assembly.MainModule.Resources.OfType<EmbeddedResource>()) {
string fileName;
Stream s = r.GetResourceStream();
s.Position = 0;
if (r.Name.EndsWith(".g.resources", StringComparison.OrdinalIgnoreCase)) {
IEnumerable<DictionaryEntry> rs = null;
try {
rs = new ResourceSet(s).Cast<DictionaryEntry>();
} catch (ArgumentException) {
}
if (rs != null && rs.All(e => e.Value is Stream)) {
foreach (var pair in rs) {
fileName = Path.Combine(((string)pair.Key).Split('/').Select(p => TextView.DecompilerTextView.CleanUpName(p)).ToArray());
string dirName = Path.GetDirectoryName(fileName);
if (!string.IsNullOrEmpty(dirName) && directories.Add(dirName)) {
Directory.CreateDirectory(Path.Combine(options.SaveAsProjectDirectory, dirName));
}
Stream entryStream = (Stream)pair.Value;
entryStream.Position = 0;
if (fileName.EndsWith(".baml", StringComparison.OrdinalIgnoreCase)) {
MemoryStream ms = new MemoryStream();
entryStream.CopyTo(ms);
BamlDecompiler decompiler = TreeNodes.ResourceEntryNode.CreateBamlDecompilerInAppDomain(ref bamlDecompilerAppDomain, assemblyFileName);
string xaml = null;
try {
xaml = decompiler.DecompileBaml(ms, assemblyFileName);
} catch (XamlXmlWriterException) {} // ignore XAML writer exceptions
if (xaml != null) {
File.WriteAllText(Path.Combine(options.SaveAsProjectDirectory, Path.ChangeExtension(fileName, ".xaml")), xaml);
yield return Tuple.Create("Page", Path.ChangeExtension(fileName, ".xaml"));
continue;
}
}
using (FileStream fs = new FileStream(Path.Combine(options.SaveAsProjectDirectory, fileName), FileMode.Create, FileAccess.Write)) {
entryStream.CopyTo(fs);
}
yield return Tuple.Create("Resource", fileName);
}
continue;
}
}
fileName = GetFileNameForResource(r.Name, directories);
using (FileStream fs = new FileStream(Path.Combine(options.SaveAsProjectDirectory, fileName), FileMode.Create, FileAccess.Write)) {
s.CopyTo(fs);
}
yield return Tuple.Create("EmbeddedResource", fileName);
}
} finally {
if (bamlDecompilerAppDomain != null)
AppDomain.Unload(bamlDecompilerAppDomain);
}
}

string GetFileNameForResource(string fullName, HashSet<string> directories)
{
string[] splitName = fullName.Split('.');
string fileName = TextView.DecompilerTextView.CleanUpName(fullName);
for (int i = splitName.Length - 1; i > 0; i--) {
string ns = string.Join(".", splitName, 0, i);
if (directories.Contains(ns)) {
string name = string.Join(".", splitName, i, splitName.Length - i);
fileName = Path.Combine(ns, TextView.DecompilerTextView.CleanUpName(name));
break;
}
}
return fileName;
}
#endregion

AstBuilder CreateAstBuilder(DecompilationOptions options, TypeDefinition currentType)
{
Expand Down
38 changes: 24 additions & 14 deletions ILSpy/TextView/DecompilerTextView.cs
Expand Up @@ -283,21 +283,31 @@ static Task<AvalonEditTextOutput> DecompileAsync(DecompilationContext context, i

Thread thread = new Thread(new ThreadStart(
delegate {
try {
AvalonEditTextOutput textOutput = new AvalonEditTextOutput();
textOutput.LengthLimit = outputLengthLimit;
DecompileNodes(context, textOutput);
textOutput.PrepareDocument();
tcs.SetResult(textOutput);
#if DEBUG
} catch (AggregateException ex) {
tcs.SetException(ex);
} catch (OperationCanceledException ex) {
tcs.SetException(ex);
#else
} catch (Exception ex) {
tcs.SetException(ex);
#if DEBUG
if (Debugger.IsAttached) {
try {
AvalonEditTextOutput textOutput = new AvalonEditTextOutput();
textOutput.LengthLimit = outputLengthLimit;
DecompileNodes(context, textOutput);
textOutput.PrepareDocument();
tcs.SetResult(textOutput);
} catch (AggregateException ex) {
tcs.SetException(ex);
} catch (OperationCanceledException ex) {
tcs.SetException(ex);
}
} else
#endif
{
try {
AvalonEditTextOutput textOutput = new AvalonEditTextOutput();
textOutput.LengthLimit = outputLengthLimit;
DecompileNodes(context, textOutput);
textOutput.PrepareDocument();
tcs.SetResult(textOutput);
} catch (Exception ex) {
tcs.SetException(ex);
}
}
}));
thread.Start();
Expand Down

0 comments on commit 0c2a2ab

Please sign in to comment.