Browse Source

Simplify debug symbols generated by ILSpy

pull/32/merge
David Srbecký 13 years ago
parent
commit
4f68861544
  1. 2
      src/Libraries/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  2. 39
      src/Libraries/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs
  3. 231
      src/Libraries/ICSharpCode.Decompiler/CodeMappings.cs
  4. 26
      src/Libraries/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs
  5. 11
      src/Libraries/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs
  6. 2
      src/Libraries/ICSharpCode.Decompiler/ITextOutput.cs
  7. 2
      src/Libraries/ICSharpCode.Decompiler/PlainTextOutput.cs

2
src/Libraries/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -126,7 +126,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -126,7 +126,7 @@ namespace ICSharpCode.Decompiler.Ast
astBlock.Statements.InsertBefore(insertionPoint, newVarDecl);
}
astBlock.AddAnnotation(new MemberMapping(methodDef) { LocalVariables = localVariables });
astBlock.AddAnnotation(new MethodDebugSymbols(methodDef) { LocalVariables = localVariables.ToList() });
return astBlock;
}

39
src/Libraries/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs

@ -265,8 +265,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -265,8 +265,7 @@ namespace ICSharpCode.Decompiler.Ast
}
Stack<TextLocation> startLocations = new Stack<TextLocation>();
MemberMapping currentMemberMapping;
Stack<MemberMapping> parentMemberMappings = new Stack<MemberMapping>();
Stack<MethodDebugSymbols> symbolsStack = new Stack<MethodDebugSymbols>();
public void StartNode(AstNode node)
{
@ -285,10 +284,9 @@ namespace ICSharpCode.Decompiler.Ast @@ -285,10 +284,9 @@ namespace ICSharpCode.Decompiler.Ast
if (node is EntityDeclaration && node.Annotation<MemberReference>() != null && node.GetChildByRole(Roles.Identifier).IsNull)
output.WriteDefinition("", node.Annotation<MemberReference>(), false);
MemberMapping mapping = node.Annotation<MemberMapping>();
if (mapping != null) {
parentMemberMappings.Push(currentMemberMapping);
currentMemberMapping = mapping;
if (node.Annotation<MethodDebugSymbols>() != null) {
symbolsStack.Push(node.Annotation<MethodDebugSymbols>());
symbolsStack.Peek().StartLocation = startLocations.Peek();
}
}
@ -305,26 +303,19 @@ namespace ICSharpCode.Decompiler.Ast @@ -305,26 +303,19 @@ namespace ICSharpCode.Decompiler.Ast
var startLocation = startLocations.Pop();
// code mappings
if (currentMemberMapping != null) {
var ranges = node.Annotation<List<ILRange>>();
if (ranges != null && ranges.Count > 0) {
// add all ranges
foreach (var range in ranges) {
currentMemberMapping.MemberCodeMappings.Add(
new SourceCodeMapping {
ILInstructionOffset = range,
StartLocation = startLocation,
EndLocation = output.Location,
MemberMapping = currentMemberMapping
});
}
}
var ranges = node.Annotation<List<ILRange>>();
if (symbolsStack.Count > 0 && ranges != null && ranges.Count > 0) {
symbolsStack.Peek().SequencePoints.Add(
new SequencePoint() {
ILRanges = ranges,
StartLocation = startLocation,
EndLocation = output.Location
});
}
if (node.Annotation<MemberMapping>() != null) {
output.AddDebuggerMemberMapping(currentMemberMapping);
currentMemberMapping = parentMemberMappings.Pop();
if (node.Annotation<MethodDebugSymbols>() != null) {
symbolsStack.Peek().EndLocation = output.Location;
output.AddDebugSymbols(symbolsStack.Pop());
}
}

231
src/Libraries/ICSharpCode.Decompiler/CodeMappings.cs

@ -17,240 +17,35 @@ @@ -17,240 +17,35 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.Decompiler.Ast;
using ICSharpCode.Decompiler.Disassembler;
using ICSharpCode.Decompiler.ILAst;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil;
namespace ICSharpCode.Decompiler
{
/// <summary>
/// Maps the source code to IL.
/// </summary>
public sealed class SourceCodeMapping
/// <summary> Maps method's source code to IL </summary>
public class MethodDebugSymbols
{
/// <summary>
/// Gets or sets the start location of the instruction.
/// </summary>
public MethodDefinition CecilMethod { get; set; }
public List<ILVariable> LocalVariables { get; set; }
public List<SequencePoint> SequencePoints { get; set; }
public TextLocation StartLocation { get; set; }
/// <summary>
/// Gets or sets the end location of the instruction.
/// </summary>
public TextLocation EndLocation { get; set; }
/// <summary>
/// Gets or sets IL Range offset for the source code line. E.g.: 13-19 &lt;-&gt; 135.
/// </summary>
public ILRange ILInstructionOffset { get; set; }
/// <summary>
/// Gets or sets the member mapping this source code mapping belongs to.
/// </summary>
public MemberMapping MemberMapping { get; set; }
/// <summary>
/// Retrieves the array that contains the IL range and the missing gaps between ranges.
/// </summary>
/// <returns>The array representation of the step aranges.</returns>
public int[] ToArray(bool isMatch)
{
var currentList = new List<ILRange>();
// add list for the current source code line
currentList.AddRange(ILRange.OrderAndJoint(MemberMapping.MemberCodeMappings
.FindAll(m => m.StartLocation.Line == this.StartLocation.Line)
.ConvertAll<ILRange>(m => m.ILInstructionOffset)));
if (!isMatch) {
// add inverted
currentList.AddRange(MemberMapping.InvertedList);
} else {
// if the current list contains the last mapping, add also the last gap
var lastInverted = MemberMapping.InvertedList.LastOrDefault();
if (lastInverted != null && lastInverted.From == currentList[currentList.Count - 1].To)
currentList.Add(lastInverted);
}
// set the output
var resultList = new List<int>();
foreach (var element in ILRange.OrderAndJoint(currentList)) {
resultList.Add(element.From);
resultList.Add(element.To);
}
return resultList.ToArray();
}
}
/// <summary>
/// Stores the member information and its source code mappings.
/// </summary>
public sealed class MemberMapping
{
IEnumerable<ILRange> invertedList;
internal MemberMapping()
{
}
public MemberMapping(MethodDefinition method)
{
this.MetadataToken = method.MetadataToken.ToInt32();
this.MemberCodeMappings = new List<SourceCodeMapping>();
this.MemberReference = method;
this.CodeSize = method.Body.CodeSize;
}
/// <summary>
/// Gets or sets the type of the mapping.
/// </summary>
public MemberReference MemberReference { get; internal set; }
/// <summary>
/// Metadata token of the member.
/// </summary>
public int MetadataToken { get; internal set; }
/// <summary>
/// Gets or sets the code size for the member mapping.
/// </summary>
public int CodeSize { get; internal set; }
/// <summary>
/// Gets or sets the source code mappings.
/// </summary>
public List<SourceCodeMapping> MemberCodeMappings { get; internal set; }
/// <summary>
/// Gets or sets the local variables.
/// </summary>
public IEnumerable<ILVariable> LocalVariables { get; internal set; }
/// <summary>
/// Gets the inverted IL Ranges.<br/>
/// E.g.: for (0-9, 11-14, 14-18, 21-25) => (9-11,18-21).
/// </summary>
/// <returns>IL Range inverted list.</returns>
public IEnumerable<ILRange> InvertedList
public MethodDebugSymbols(MethodDefinition methodDef)
{
get {
if (invertedList == null) {
var list = MemberCodeMappings.ConvertAll<ILRange>(
s => new ILRange { From = s.ILInstructionOffset.From, To = s.ILInstructionOffset.To });
invertedList = ILRange.OrderAndJoint(ILRange.Invert(list, CodeSize));
}
return invertedList;
}
this.CecilMethod = methodDef;
this.LocalVariables = new List<ILVariable>();
this.SequencePoints = new List<SequencePoint>();
}
}
/// <summary>
/// Code mappings helper class.
/// </summary>
public static class CodeMappings
public class SequencePoint
{
/// <summary>
/// Gets source code mapping and metadata token based on type name and line number.
/// </summary>
/// <param name="codeMappings">Code mappings storage.</param>
/// <param name="typeName">Member reference name.</param>
/// <param name="lineNumber">Line number.</param>
/// <param name="metadataToken">Metadata token.</param>
/// <returns></returns>
public static SourceCodeMapping GetInstructionByLineNumber(
this MemberMapping codeMapping,
int lineNumber,
out int metadataToken)
{
if (codeMapping == null)
throw new ArgumentException("CodeMappings storage must be valid!");
var map = codeMapping.MemberCodeMappings.Find(m => m.StartLocation.Line == lineNumber);
if (map != null) {
metadataToken = codeMapping.MetadataToken;
return map;
}
metadataToken = 0;
return null;
}
/// <summary>
/// Gets a mapping given a type, a token and an IL offset.
/// </summary>
/// <param name="codeMappings">Code mappings storage.</param>
/// <param name="token">Token.</param>
/// <param name="ilOffset">IL offset.</param>
/// <param name="isMatch">True, if perfect match.</param>
/// <returns>A code mapping.</returns>
public static SourceCodeMapping GetInstructionByTokenAndOffset(
this MemberMapping codeMapping,
int ilOffset,
out bool isMatch)
{
isMatch = false;
if (codeMapping == null)
throw new ArgumentNullException("CodeMappings storage must be valid!");
// try find an exact match
var map = codeMapping.MemberCodeMappings.Find(m => m.ILInstructionOffset.From <= ilOffset && ilOffset < m.ILInstructionOffset.To);
if (map == null) {
// get the immediate next one
map = codeMapping.MemberCodeMappings.Find(m => m.ILInstructionOffset.From > ilOffset);
isMatch = false;
if (map == null)
map = codeMapping.MemberCodeMappings.LastOrDefault(); // get the last
return map;
}
isMatch = true;
return map;
}
/// <summary>
/// Gets the source code and type name from metadata token and offset.
/// </summary>
/// <param name="codeMappings">Code mapping storage.</param>
/// <param name="token">Metadata token.</param>
/// <param name="ilOffset">IL offset.</param>
/// <param name="typeName">Type definition.</param>
/// <param name="line">Line number.</param>
/// <remarks>It is possible to exist to different types from different assemblies with the same metadata token.</remarks>
public static bool GetInstructionByTokenAndOffset(
this MemberMapping mapping,
int ilOffset,
out MemberReference member,
out int line)
{
member = null;
line = 0;
if (mapping == null)
throw new ArgumentException("CodeMappings storage must be valid!");
var codeMapping = mapping.MemberCodeMappings.Find(
cm => cm.ILInstructionOffset.From <= ilOffset && ilOffset <= cm.ILInstructionOffset.To - 1);
if (codeMapping == null) {
codeMapping = mapping.MemberCodeMappings.Find(cm => cm.ILInstructionOffset.From > ilOffset);
if (codeMapping == null) {
codeMapping = mapping.MemberCodeMappings.LastOrDefault();
if (codeMapping == null)
return false;
}
}
member = mapping.MemberReference;
line = codeMapping.StartLocation.Line;
return true;
}
public List<ILRange> ILRanges { get; set; }
public TextLocation StartLocation { get; set; }
public TextLocation EndLocation { get; set; }
}
}

26
src/Libraries/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs

@ -47,7 +47,7 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -47,7 +47,7 @@ namespace ICSharpCode.Decompiler.Disassembler
this.cancellationToken = cancellationToken;
}
public void Disassemble(MethodBody body, MemberMapping methodMapping)
public void Disassemble(MethodBody body, MethodDebugSymbols debugSymbols)
{
// start writing IL code
MethodDefinition method = body.Method;
@ -82,20 +82,19 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -82,20 +82,19 @@ namespace ICSharpCode.Decompiler.Disassembler
if (detectControlStructure && body.Instructions.Count > 0) {
Instruction inst = body.Instructions[0];
HashSet<int> branchTargets = GetBranchTargets(body.Instructions);
WriteStructureBody(new ILStructure(body), branchTargets, ref inst, methodMapping, method.Body.CodeSize);
WriteStructureBody(new ILStructure(body), branchTargets, ref inst, debugSymbols, method.Body.CodeSize);
} else {
foreach (var inst in method.Body.Instructions) {
var startLocation = output.Location;
inst.WriteTo(output);
if (methodMapping != null) {
if (debugSymbols != null) {
// add IL code mappings - used in debugger
methodMapping.MemberCodeMappings.Add(
new SourceCodeMapping() {
debugSymbols.SequencePoints.Add(
new SequencePoint() {
StartLocation = output.Location,
EndLocation = output.Location,
ILInstructionOffset = new ILRange { From = inst.Offset, To = inst.Next == null ? method.Body.CodeSize : inst.Next.Offset },
MemberMapping = methodMapping
ILRanges = new List<ILRange>() { new ILRange { From = inst.Offset, To = inst.Next == null ? method.Body.CodeSize : inst.Next.Offset } }
});
}
@ -174,7 +173,7 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -174,7 +173,7 @@ namespace ICSharpCode.Decompiler.Disassembler
output.Indent();
}
void WriteStructureBody(ILStructure s, HashSet<int> branchTargets, ref Instruction inst, MemberMapping currentMethodMapping, int codeSize)
void WriteStructureBody(ILStructure s, HashSet<int> branchTargets, ref Instruction inst, MethodDebugSymbols debugSymbols, int codeSize)
{
bool isFirstInstructionInStructure = true;
bool prevInstructionWasBranch = false;
@ -184,7 +183,7 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -184,7 +183,7 @@ namespace ICSharpCode.Decompiler.Disassembler
if (childIndex < s.Children.Count && s.Children[childIndex].StartOffset <= offset && offset < s.Children[childIndex].EndOffset) {
ILStructure child = s.Children[childIndex++];
WriteStructureHeader(child);
WriteStructureBody(child, branchTargets, ref inst, currentMethodMapping, codeSize);
WriteStructureBody(child, branchTargets, ref inst, debugSymbols, codeSize);
WriteStructureFooter(child);
} else {
if (!isFirstInstructionInStructure && (prevInstructionWasBranch || branchTargets.Contains(offset))) {
@ -194,13 +193,12 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -194,13 +193,12 @@ namespace ICSharpCode.Decompiler.Disassembler
inst.WriteTo(output);
// add IL code mappings - used in debugger
if (currentMethodMapping != null) {
currentMethodMapping.MemberCodeMappings.Add(
new SourceCodeMapping() {
if (debugSymbols != null) {
debugSymbols.SequencePoints.Add(
new SequencePoint() {
StartLocation = startLocation,
EndLocation = output.Location,
ILInstructionOffset = new ILRange { From = inst.Offset, To = inst.Next == null ? codeSize : inst.Next.Offset },
MemberMapping = currentMethodMapping
ILRanges = new List<ILRange>() { new ILRange { From = inst.Offset, To = inst.Next == null ? codeSize : inst.Next.Offset } }
});
}

11
src/Libraries/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs

@ -22,6 +22,7 @@ using System.Diagnostics; @@ -22,6 +22,7 @@ using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using ICSharpCode.NRefactory;
using Mono.Cecil;
using Mono.Collections.Generic;
@ -114,6 +115,8 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -114,6 +115,8 @@ namespace ICSharpCode.Decompiler.Disassembler
// instance default class [mscorlib]System.IO.TextWriter get_BaseWriter () cil managed
//
TextLocation startLocation = output.Location;
//emit flags
WriteEnum(method.Attributes & MethodAttributes.MemberAccessMask, methodVisibility);
WriteFlags(method.Attributes & ~MethodAttributes.MemberAccessMask, methodAttributeFlags);
@ -217,9 +220,11 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -217,9 +220,11 @@ namespace ICSharpCode.Decompiler.Disassembler
if (method.HasBody) {
// create IL code mappings - used in debugger
MemberMapping methodMapping = new MemberMapping(method);
methodBodyDisassembler.Disassemble(method.Body, methodMapping);
output.AddDebuggerMemberMapping(methodMapping);
MethodDebugSymbols debugSymbols = new MethodDebugSymbols(method);
debugSymbols.StartLocation = startLocation;
methodBodyDisassembler.Disassemble(method.Body, debugSymbols);
debugSymbols.EndLocation = output.Location;
output.AddDebugSymbols(debugSymbols);
}
CloseBlock("end of method " + DisassemblerHelpers.Escape(method.DeclaringType.Name) + "::" + DisassemblerHelpers.Escape(method.Name));

2
src/Libraries/ICSharpCode.Decompiler/ITextOutput.cs

@ -35,7 +35,7 @@ namespace ICSharpCode.Decompiler @@ -35,7 +35,7 @@ namespace ICSharpCode.Decompiler
void WriteDefinition(string text, object definition, bool isLocal = true);
void WriteReference(string text, object reference, bool isLocal = false);
void AddDebuggerMemberMapping(MemberMapping memberMapping);
void AddDebugSymbols(MethodDebugSymbols methodDebugSymbols);
void MarkFoldStart(string collapsedText = "...", bool defaultCollapsed = false);
void MarkFoldEnd();

2
src/Libraries/ICSharpCode.Decompiler/PlainTextOutput.cs

@ -115,7 +115,7 @@ namespace ICSharpCode.Decompiler @@ -115,7 +115,7 @@ namespace ICSharpCode.Decompiler
{
}
void ITextOutput.AddDebuggerMemberMapping(MemberMapping memberMapping)
void ITextOutput.AddDebugSymbols(MethodDebugSymbols methodDebugSymbols)
{
}
}

Loading…
Cancel
Save