Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/cecil.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJb Evain <jbevain@gmail.com>2017-03-21 04:07:37 +0300
committerGitHub <noreply@github.com>2017-03-21 04:07:37 +0300
commit22e15aca479e847f146f8af6e132735d47d66053 (patch)
treef2b49068b35cb43c51eace1dc8f9e3d95f726cac /symbols
parent73b54c68399f39668a2cb774428a7e659f08a761 (diff)
parentfebdb3594335753282f87e8eb37451704eb7a927 (diff)
Merge pull request #353 from jbevain/native-pdb-integration
Native pdb integration
Diffstat (limited to 'symbols')
-rw-r--r--symbols/pdb/Microsoft.Cci.Pdb/PdbFunction.cs4
-rw-r--r--symbols/pdb/Mono.Cecil.Pdb/ISymUnmanagedWriter2.cs9
-rw-r--r--symbols/pdb/Mono.Cecil.Pdb/NativePdbReader.cs119
-rw-r--r--symbols/pdb/Mono.Cecil.Pdb/NativePdbWriter.cs238
-rw-r--r--symbols/pdb/Mono.Cecil.Pdb/SymWriter.cs17
-rw-r--r--symbols/pdb/Test/Mono.Cecil.Tests/PdbTests.cs206
-rw-r--r--symbols/pdb/Test/Resources/assemblies/ComplexPdb.cs71
-rw-r--r--symbols/pdb/Test/Resources/assemblies/ComplexPdb.dllbin0 -> 7680 bytes
-rw-r--r--symbols/pdb/Test/Resources/assemblies/ComplexPdb.pdbbin0 -> 15872 bytes
9 files changed, 644 insertions, 20 deletions
diff --git a/symbols/pdb/Microsoft.Cci.Pdb/PdbFunction.cs b/symbols/pdb/Microsoft.Cci.Pdb/PdbFunction.cs
index 2ef733f..b02b97f 100644
--- a/symbols/pdb/Microsoft.Cci.Pdb/PdbFunction.cs
+++ b/symbols/pdb/Microsoft.Cci.Pdb/PdbFunction.cs
@@ -29,7 +29,7 @@ namespace Microsoft.Cci.Pdb {
internal uint segment;
internal uint address;
- //internal uint length;
+ internal uint length;
//internal byte[] metadata;
internal PdbScope[] scopes;
@@ -208,7 +208,7 @@ namespace Microsoft.Cci.Pdb {
//this.flags = proc.flags;
this.segment = proc.seg;
this.address = proc.off;
- //this.length = proc.len;
+ this.length = proc.len;
if (proc.seg != 1) {
throw new PdbDebugException("Segment is {0}, not 1.", proc.seg);
diff --git a/symbols/pdb/Mono.Cecil.Pdb/ISymUnmanagedWriter2.cs b/symbols/pdb/Mono.Cecil.Pdb/ISymUnmanagedWriter2.cs
index c8d1340..06757c2 100644
--- a/symbols/pdb/Mono.Cecil.Pdb/ISymUnmanagedWriter2.cs
+++ b/symbols/pdb/Mono.Cecil.Pdb/ISymUnmanagedWriter2.cs
@@ -40,7 +40,7 @@ namespace Mono.Cecil.Pdb {
void DefineField_Placeholder ();
void DefineGlobalVariable_Placeholder ();
void Close ();
- void SetSymAttribute_Placeholder ();
+ void SetSymAttribute (uint parent, string name, uint data, IntPtr signature);
void OpenNamespace ([In, MarshalAs (UnmanagedType.LPWStr)] string name);
void CloseNamespace ();
void UsingNamespace ([In, MarshalAs (UnmanagedType.LPWStr)] string fullName);
@@ -78,6 +78,13 @@ namespace Mono.Cecil.Pdb {
[In] int addr3,
[In] int startOffset,
[In] int endOffset);
+
+ void DefineGlobalVariable2_Placeholder ();
+
+ void DefineConstant2 (
+ [In, MarshalAs (UnmanagedType.LPWStr)] string name,
+ [In, MarshalAs (UnmanagedType.Struct)] object variant,
+ [In] SymbolToken sigToken);
}
}
diff --git a/symbols/pdb/Mono.Cecil.Pdb/NativePdbReader.cs b/symbols/pdb/Mono.Cecil.Pdb/NativePdbReader.cs
index 96479cd..781e605 100644
--- a/symbols/pdb/Mono.Cecil.Pdb/NativePdbReader.cs
+++ b/symbols/pdb/Mono.Cecil.Pdb/NativePdbReader.cs
@@ -28,6 +28,7 @@ namespace Mono.Cecil.Pdb {
readonly Disposable<Stream> pdb_file;
readonly Dictionary<string, Document> documents = new Dictionary<string, Document> ();
readonly Dictionary<uint, PdbFunction> functions = new Dictionary<uint, PdbFunction> ();
+ readonly Dictionary<PdbScope, ImportDebugInformation> imports = new Dictionary<PdbScope, ImportDebugInformation> ();
internal NativePdbReader (Disposable<Stream> file)
{
@@ -120,8 +121,12 @@ namespace Mono.Cecil.Pdb {
ReadSequencePoints (function, symbol);
- if (!function.scopes.IsNullOrEmpty())
- symbol.scope = ReadScopeAndLocals (function.scopes [0], symbol);
+ symbol.scope = !function.scopes.IsNullOrEmpty ()
+ ? ReadScopeAndLocals (function.scopes [0], symbol)
+ : new ScopeDebugInformation { Start = new InstructionOffset (0), End = new InstructionOffset ((int) function.length) };
+
+ if (function.tokenOfMethodWhoseUsingInfoAppliesToThisMethod != method.MetadataToken.ToUInt32 () && function.tokenOfMethodWhoseUsingInfoAppliesToThisMethod != 0)
+ symbol.scope.import = GetImport (function.tokenOfMethodWhoseUsingInfoAppliesToThisMethod, method.Module);
if (function.scopes.Length > 1) {
for (int i = 1; i < function.scopes.Length; i++) {
@@ -131,10 +136,28 @@ namespace Mono.Cecil.Pdb {
}
}
+ if (function.iteratorScopes != null)
+ foreach (var iterator_scope in function.iteratorScopes)
+ symbol.CustomDebugInformations.Add (new StateMachineScopeDebugInformation ((int) iterator_scope.Offset, (int) (iterator_scope.Offset + iterator_scope.Length + 1)));
+
+ if (function.synchronizationInformation != null) {
+ var async_debug_info = new AsyncMethodBodyDebugInformation ((int) function.synchronizationInformation.GeneratedCatchHandlerOffset);
+
+ foreach (var synchronization_point in function.synchronizationInformation.synchronizationPoints) {
+ async_debug_info.Yields.Add (new InstructionOffset ((int) synchronization_point.SynchronizeOffset));
+ async_debug_info.Resumes.Add (new InstructionOffset ((int) synchronization_point.ContinuationOffset));
+ }
+
+ symbol.CustomDebugInformations.Add (async_debug_info);
+
+ async_debug_info.MoveNextMethod = method;
+ symbol.StateMachineKickOffMethod = (MethodDefinition) method.Module.LookupToken ((int) function.synchronizationInformation.kickoffMethodToken);
+ }
+
return symbol;
}
- static Collection<ScopeDebugInformation> ReadScopeAndLocals (PdbScope [] scopes, MethodDebugInformation info)
+ Collection<ScopeDebugInformation> ReadScopeAndLocals (PdbScope [] scopes, MethodDebugInformation info)
{
var symbols = new Collection<ScopeDebugInformation> (scopes.Length);
@@ -145,13 +168,13 @@ namespace Mono.Cecil.Pdb {
return symbols;
}
- static ScopeDebugInformation ReadScopeAndLocals (PdbScope scope, MethodDebugInformation info)
+ ScopeDebugInformation ReadScopeAndLocals (PdbScope scope, MethodDebugInformation info)
{
var parent = new ScopeDebugInformation ();
parent.Start = new InstructionOffset ((int) scope.offset);
parent.End = new InstructionOffset ((int) (scope.offset + scope.length));
- if (!scope.slots.IsNullOrEmpty()) {
+ if (!scope.slots.IsNullOrEmpty ()) {
parent.variables = new Collection<VariableDebugInformation> (scope.slots.Length);
foreach (PdbSlot slot in scope.slots) {
@@ -170,10 +193,24 @@ namespace Mono.Cecil.Pdb {
parent.constants = new Collection<ConstantDebugInformation> (scope.constants.Length);
foreach (var constant in scope.constants) {
- parent.constants.Add (new ConstantDebugInformation (
- constant.name,
- (TypeReference) info.method.Module.LookupToken ((int) constant.token),
- constant.value));
+ var type = info.Method.Module.Read (constant, (c, r) => r.ReadConstantSignature (new MetadataToken (c.token)));
+ var value = constant.value;
+
+ // Object "null" is encoded as integer
+ if (type != null && !type.IsValueType && value is int && (int) value == 0)
+ value = null;
+
+ parent.constants.Add (new ConstantDebugInformation (constant.name, type, value));
+ }
+ }
+
+ if (!scope.usedNamespaces.IsNullOrEmpty ()) {
+ ImportDebugInformation import;
+ if (imports.TryGetValue (scope, out import)) {
+ parent.import = import;
+ } else {
+ import = GetImport (scope, info.Method.Module);
+ imports.Add (scope, import);
}
}
@@ -197,6 +234,70 @@ namespace Mono.Cecil.Pdb {
return false;
}
+ ImportDebugInformation GetImport (uint token, ModuleDefinition module)
+ {
+ PdbFunction function;
+ if (!functions.TryGetValue (token, out function))
+ return null;
+
+ if (function.scopes.Length != 1)
+ return null;
+
+ var scope = function.scopes [0];
+
+ ImportDebugInformation import;
+ if (imports.TryGetValue (scope, out import))
+ return import;
+
+ import = GetImport (scope, module);
+ imports.Add (scope, import);
+ return import;
+ }
+
+ static ImportDebugInformation GetImport (PdbScope scope, ModuleDefinition module)
+ {
+ if (scope.usedNamespaces.IsNullOrEmpty ())
+ return null;
+
+ var import = new ImportDebugInformation ();
+
+ foreach (var used_namespace in scope.usedNamespaces) {
+ ImportTarget target = null;
+ var value = used_namespace.Substring (1);
+ switch (used_namespace [0]) {
+ case 'U':
+ target = new ImportTarget (ImportTargetKind.ImportNamespace) { @namespace = value };
+ break;
+ case 'T': {
+ var type = module.GetType (value, runtimeName: true);
+ if (type != null)
+ target = new ImportTarget (ImportTargetKind.ImportType) { type = type };
+ break;
+ }
+ case 'A':
+ var index = used_namespace.IndexOf(' ');
+ var alias_value = used_namespace.Substring (1, index - 1);
+ var alias_target_value = used_namespace.Substring (index + 2);
+ switch (used_namespace [index + 1]) {
+ case 'U':
+ target = new ImportTarget (ImportTargetKind.DefineNamespaceAlias) { alias = alias_value, @namespace = alias_target_value };
+ break;
+ case 'T':
+ var type = module.GetType (alias_target_value, runtimeName: true);
+ if (type != null)
+ target = new ImportTarget (ImportTargetKind.DefineTypeAlias) { alias = alias_value, type = type };
+ break;
+ }
+ break;
+ }
+
+ if (target != null)
+ import.Targets.Add (target);
+ }
+
+ return import;
+ }
+
void ReadSequencePoints (PdbFunction function, MethodDebugInformation info)
{
if (function.lines == null)
diff --git a/symbols/pdb/Mono.Cecil.Pdb/NativePdbWriter.cs b/symbols/pdb/Mono.Cecil.Pdb/NativePdbWriter.cs
index 663e34c..8a2f01f 100644
--- a/symbols/pdb/Mono.Cecil.Pdb/NativePdbWriter.cs
+++ b/symbols/pdb/Mono.Cecil.Pdb/NativePdbWriter.cs
@@ -11,25 +11,33 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.SymbolStore;
+using System.IO;
+using System.Linq;
+using System.Text;
using Mono.Cecil.Cil;
+using Mono.Cecil.PE;
using Mono.Collections.Generic;
#if !READ_ONLY
namespace Mono.Cecil.Pdb {
- public class NativePdbWriter : Cil.ISymbolWriter {
+ public class NativePdbWriter : Cil.ISymbolWriter, Cil.IMetadataSymbolWriter {
readonly ModuleDefinition module;
readonly SymWriter writer;
readonly Dictionary<string, SymDocumentWriter> documents;
+ readonly Dictionary<ImportDebugInformation, MetadataToken> import_info_to_parent;
+
+ MetadataBuilder metadata;
internal NativePdbWriter (ModuleDefinition module, SymWriter writer)
{
this.module = module;
this.writer = writer;
this.documents = new Dictionary<string, SymDocumentWriter> ();
+ this.import_info_to_parent = new Dictionary<ImportDebugInformation, MetadataToken> ();
}
public ISymbolReaderProvider GetReaderProvider ()
@@ -50,38 +58,147 @@ namespace Mono.Cecil.Pdb {
var method_token = info.method.MetadataToken;
var sym_token = new SymbolToken (method_token.ToInt32 ());
+ if (!info.HasSequencePoints && info.scope == null && !info.HasCustomDebugInformations && info.StateMachineKickOffMethod == null)
+ return;
+
writer.OpenMethod (sym_token);
if (!info.sequence_points.IsNullOrEmpty ())
DefineSequencePoints (info.sequence_points);
+ var import_parent = new MetadataToken ();
+
if (info.scope != null)
- DefineScope (info.scope, info);
+ DefineScope (info.scope, info, out import_parent);
+
+ DefineCustomMetadata (info, import_parent);
writer.CloseMethod ();
}
- void DefineScope (ScopeDebugInformation scope, MethodDebugInformation info)
+ void IMetadataSymbolWriter.SetMetadata (MetadataBuilder metadata)
+ {
+ this.metadata = metadata;
+ }
+
+
+ void DefineCustomMetadata (MethodDebugInformation info, MetadataToken import_parent)
+ {
+ var metadata = new CustomMetadataWriter (this.writer);
+
+ if (import_parent.RID != 0) {
+ metadata.WriteForwardInfo (import_parent);
+ } else if (info.scope != null && info.scope.Import != null && info.scope.Import.HasTargets) {
+ metadata.WriteUsingInfo (info.scope.Import);
+ }
+
+ if (info.Method.HasCustomAttributes) {
+ foreach (var attribute in info.Method.CustomAttributes) {
+ const string compiler_services = "System.Runtime.CompilerServices";
+ var attribute_type = attribute.AttributeType;
+
+ if (!attribute_type.IsTypeOf (compiler_services, "IteratorStateMachineAttribute") && !attribute_type.IsTypeOf (compiler_services, "AsyncStateMachineAttribute"))
+ continue;
+
+ var type = attribute.ConstructorArguments [0].Value as TypeReference;
+ if (type == null)
+ continue;
+
+ metadata.WriteForwardIterator (type);
+ }
+ }
+
+ if (info.HasCustomDebugInformations) {
+ var scopes = info.CustomDebugInformations.OfType<StateMachineScopeDebugInformation> ().ToArray ();
+
+ if (scopes.Length > 0)
+ metadata.WriteIteratorScopes (scopes, info);
+ }
+
+ metadata.WriteCustomMetadata ();
+
+ DefineAsyncCustomMetadata (info);
+ }
+
+ void DefineAsyncCustomMetadata (MethodDebugInformation info)
+ {
+ if (!info.HasCustomDebugInformations)
+ return;
+
+ foreach (var custom_info in info.CustomDebugInformations) {
+ var async_debug_info = custom_info as AsyncMethodBodyDebugInformation;
+ if (async_debug_info == null)
+ continue;
+
+ using (var stream = new MemoryStream ()) {
+ var async_metadata = new BinaryStreamWriter (stream);
+ async_metadata.WriteUInt32 (info.StateMachineKickOffMethod != null ? info.StateMachineKickOffMethod.MetadataToken.ToUInt32 () : 0);
+ async_metadata.WriteUInt32 ((uint) async_debug_info.CatchHandler.Offset);
+ async_metadata.WriteUInt32 ((uint) async_debug_info.Resumes.Count);
+ for (int i = 0; i < async_debug_info.Resumes.Count; ++i) {
+ async_metadata.WriteUInt32 ((uint) async_debug_info.Yields [i].Offset);
+ async_metadata.WriteUInt32 (async_debug_info.MoveNextMethod != null ? async_debug_info.MoveNextMethod.MetadataToken.ToUInt32 () : 0);
+ async_metadata.WriteUInt32 ((uint) async_debug_info.Resumes [i].Offset);
+ }
+
+ writer.DefineCustomMetadata ("asyncMethodInfo", stream.ToArray ());
+ }
+ }
+ }
+
+ void DefineScope (ScopeDebugInformation scope, MethodDebugInformation info, out MetadataToken import_parent)
{
var start_offset = scope.Start.Offset;
var end_offset = scope.End.IsEndOfMethod
? info.code_size
: scope.End.Offset;
+ import_parent = new MetadataToken (0u);
+
writer.OpenScope (start_offset);
+ if (scope.Import != null && scope.Import.HasTargets && !import_info_to_parent.TryGetValue (info.scope.Import, out import_parent)) {
+ foreach (var target in scope.Import.Targets) {
+ switch (target.Kind) {
+ case ImportTargetKind.ImportNamespace:
+ writer.UsingNamespace ("U" + target.@namespace);
+ break;
+ case ImportTargetKind.ImportType:
+ writer.UsingNamespace ("T" + TypeParser.ToParseable (target.type));
+ break;
+ case ImportTargetKind.DefineNamespaceAlias:
+ writer.UsingNamespace ("A" + target.Alias + " U" + target.@namespace);
+ break;
+ case ImportTargetKind.DefineTypeAlias:
+ writer.UsingNamespace ("A" + target.Alias + " T" + TypeParser.ToParseable (target.type));
+ break;
+ }
+ }
+
+ import_info_to_parent.Add (info.scope.Import, info.method.MetadataToken);
+ }
+
var sym_token = new SymbolToken (info.local_var_token.ToInt32 ());
if (!scope.variables.IsNullOrEmpty ()) {
for (int i = 0; i < scope.variables.Count; i++) {
var variable = scope.variables [i];
- CreateLocalVariable (variable, sym_token, start_offset, end_offset);
+ DefineLocalVariable (variable, sym_token, start_offset, end_offset);
+ }
+ }
+
+ if (!scope.constants.IsNullOrEmpty ()) {
+ for (int i = 0; i < scope.constants.Count; i++) {
+ var constant = scope.constants [i];
+ DefineConstant (constant);
}
}
if (!scope.scopes.IsNullOrEmpty ()) {
- for (int i = 0; i < scope.scopes.Count; i++)
- DefineScope (scope.scopes [i], info);
+ for (int i = 0; i < scope.scopes.Count; i++) {
+ MetadataToken _;
+ DefineScope (scope.scopes [i], info, out _);
+ }
}
writer.CloseScope (end_offset);
@@ -102,7 +219,7 @@ namespace Mono.Cecil.Pdb {
}
}
- void CreateLocalVariable (VariableDebugInformation variable, SymbolToken local_var_token, int start_offset, int end_offset)
+ void DefineLocalVariable (VariableDebugInformation variable, SymbolToken local_var_token, int start_offset, int end_offset)
{
writer.DefineLocalVariable2 (
variable.Name,
@@ -116,6 +233,14 @@ namespace Mono.Cecil.Pdb {
end_offset);
}
+ void DefineConstant (ConstantDebugInformation constant)
+ {
+ var row = metadata.AddStandAloneSignature (metadata.GetConstantTypeBlobIndex (constant.ConstantType));
+ var token = new MetadataToken (TokenType.Signature, row);
+
+ writer.DefineConstant2 (constant.Name, constant.Value, new SymbolToken (token.ToInt32 ()));
+ }
+
SymDocumentWriter GetDocument (Document document)
{
if (document == null)
@@ -144,6 +269,105 @@ namespace Mono.Cecil.Pdb {
writer.Close ();
}
}
+
+ enum CustomMetadataType : byte {
+ UsingInfo = 0,
+ ForwardInfo = 1,
+ IteratorScopes = 3,
+ ForwardIterator = 4,
+ }
+
+ class CustomMetadataWriter : IDisposable {
+
+ readonly SymWriter sym_writer;
+ readonly MemoryStream stream;
+ readonly BinaryStreamWriter writer;
+
+ int count;
+
+ const byte version = 4;
+
+ public CustomMetadataWriter (SymWriter sym_writer)
+ {
+ this.sym_writer = sym_writer;
+ this.stream = new MemoryStream ();
+ this.writer = new BinaryStreamWriter (stream);
+
+ writer.WriteByte (version);
+ writer.WriteByte (0); // count
+ writer.Align (4);
+ }
+
+ public void WriteUsingInfo (ImportDebugInformation import_info)
+ {
+ Write (CustomMetadataType.UsingInfo, () => {
+ writer.WriteUInt16 ((ushort) 1);
+ writer.WriteUInt16 ((ushort) import_info.Targets.Count);
+ });
+ }
+
+ public void WriteForwardInfo (MetadataToken import_parent)
+ {
+ Write (CustomMetadataType.ForwardInfo, () => writer.WriteUInt32 (import_parent.ToUInt32 ()));
+ }
+
+ public void WriteIteratorScopes (StateMachineScopeDebugInformation [] scopes, MethodDebugInformation debug_info)
+ {
+ Write (CustomMetadataType.IteratorScopes, () => {
+ writer.WriteInt32 (scopes.Length);
+ foreach (var scope in scopes) {
+ var start = scope.Start.Offset;
+ var end = scope.End.IsEndOfMethod ? debug_info.code_size : scope.End.Offset;
+ writer.WriteInt32 (start);
+ writer.WriteInt32 (end - 1);
+ }
+ });
+ }
+
+ public void WriteForwardIterator (TypeReference type)
+ {
+ Write (CustomMetadataType.ForwardIterator, () => writer.WriteBytes(Encoding.Unicode.GetBytes(type.Name)));
+ }
+
+ void Write (CustomMetadataType type, Action write)
+ {
+ count++;
+ writer.WriteByte (version);
+ writer.WriteByte ((byte) type);
+ writer.Align (4);
+
+ var length_position = writer.Position;
+ writer.WriteUInt32 (0);
+
+ write ();
+ writer.Align (4);
+
+ var end = writer.Position;
+ var length = end - length_position + 4; // header is 4 bytes long
+
+ writer.Position = length_position;
+ writer.WriteInt32 (length);
+
+ writer.Position = end;
+ }
+
+ public void WriteCustomMetadata ()
+ {
+ if (count == 0)
+ return;
+
+ writer.BaseStream.Position = 1;
+ writer.WriteByte ((byte) count);
+ writer.Flush ();
+
+ sym_writer.DefineCustomMetadata ("MD2", stream.ToArray ());
+ }
+
+ public void Dispose ()
+ {
+ stream.Dispose ();
+ }
+ }
}
#endif
diff --git a/symbols/pdb/Mono.Cecil.Pdb/SymWriter.cs b/symbols/pdb/Mono.Cecil.Pdb/SymWriter.cs
index ab0893b..3a67e06 100644
--- a/symbols/pdb/Mono.Cecil.Pdb/SymWriter.cs
+++ b/symbols/pdb/Mono.Cecil.Pdb/SymWriter.cs
@@ -71,6 +71,16 @@ namespace Mono.Cecil.Pdb
m_writer.DefineLocalVariable2 (name, (int)attributes, sigToken, (int)addrKind, addr1, addr2, addr3, startOffset, endOffset);
}
+ public void DefineConstant2 (string name, object value, SymbolToken sigToken)
+ {
+ if (value == null) {
+ m_writer.DefineConstant2 (name, 0, sigToken);
+ return;
+ }
+
+ m_writer.DefineConstant2 (name, value, sigToken);
+ }
+
public void Close ()
{
m_writer.Close ();
@@ -145,6 +155,13 @@ namespace Mono.Cecil.Pdb
{
m_writer.UsingNamespace (fullName);
}
+
+ public void DefineCustomMetadata (string name, byte [] metadata)
+ {
+ var handle = GCHandle.Alloc (metadata, GCHandleType.Pinned);
+ m_writer.SetSymAttribute (0, name, (uint) metadata.Length, handle.AddrOfPinnedObject ());
+ handle.Free ();
+ }
}
}
diff --git a/symbols/pdb/Test/Mono.Cecil.Tests/PdbTests.cs b/symbols/pdb/Test/Mono.Cecil.Tests/PdbTests.cs
index f9f11bd..314a7b5 100644
--- a/symbols/pdb/Test/Mono.Cecil.Tests/PdbTests.cs
+++ b/symbols/pdb/Test/Mono.Cecil.Tests/PdbTests.cs
@@ -86,7 +86,6 @@ namespace Mono.Cecil.Tests {
}, readOnly: Platform.OnMono, symbolReaderProvider: typeof(PdbReaderProvider), symbolWriterProvider: typeof(PdbWriterProvider));
}
-
[Test]
public void Document ()
{
@@ -155,6 +154,211 @@ namespace Mono.Cecil.Tests {
}
[Test]
+ public void LocalVariables ()
+ {
+ TestModule ("ComplexPdb.dll", module => {
+ var type = module.GetType ("ComplexPdb.Program");
+ var method = type.GetMethod ("Bar");
+ var debug_info = method.DebugInformation;
+
+ Assert.IsNotNull (debug_info.Scope);
+ Assert.IsTrue (debug_info.Scope.HasScopes);
+ Assert.AreEqual (2, debug_info.Scope.Scopes.Count);
+
+ var scope = debug_info.Scope.Scopes [0];
+
+ Assert.IsNotNull (scope);
+ Assert.IsTrue (scope.HasVariables);
+ Assert.AreEqual (1, scope.Variables.Count);
+
+ var variable = scope.Variables [0];
+
+ Assert.AreEqual ("s", variable.Name);
+ Assert.IsFalse (variable.IsDebuggerHidden);
+ Assert.AreEqual (2, variable.Index);
+
+ scope = debug_info.Scope.Scopes [1];
+
+ Assert.IsNotNull (scope);
+ Assert.IsTrue (scope.HasVariables);
+ Assert.AreEqual (1, scope.Variables.Count);
+
+ variable = scope.Variables [0];
+
+ Assert.AreEqual ("s", variable.Name);
+ Assert.IsFalse (variable.IsDebuggerHidden);
+ Assert.AreEqual (3, variable.Index);
+
+ Assert.IsTrue (scope.HasScopes);
+ Assert.AreEqual (1, scope.Scopes.Count);
+
+ scope = scope.Scopes [0];
+
+ Assert.IsNotNull (scope);
+ Assert.IsTrue (scope.HasVariables);
+ Assert.AreEqual (1, scope.Variables.Count);
+
+ variable = scope.Variables [0];
+
+ Assert.AreEqual ("u", variable.Name);
+ Assert.IsFalse (variable.IsDebuggerHidden);
+ Assert.AreEqual (5, variable.Index);
+ }, readOnly: Platform.OnMono, symbolReaderProvider: typeof (PdbReaderProvider), symbolWriterProvider: typeof (PdbWriterProvider));
+ }
+
+ [Test]
+ public void LocalConstants ()
+ {
+ TestModule ("ComplexPdb.dll", module => {
+ var type = module.GetType ("ComplexPdb.Program");
+ var method = type.GetMethod ("Bar");
+ var debug_info = method.DebugInformation;
+
+ Assert.IsNotNull (debug_info.Scope);
+ Assert.IsTrue (debug_info.Scope.HasScopes);
+ Assert.AreEqual (2, debug_info.Scope.Scopes.Count);
+
+ var scope = debug_info.Scope.Scopes [1];
+
+ Assert.IsNotNull (scope);
+ Assert.IsTrue (scope.HasConstants);
+ Assert.AreEqual (2, scope.Constants.Count);
+
+ var constant = scope.Constants [0];
+
+ Assert.AreEqual ("b", constant.Name);
+ Assert.AreEqual (12, constant.Value);
+ Assert.AreEqual (MetadataType.Int32, constant.ConstantType.MetadataType);
+
+ constant = scope.Constants [1];
+ Assert.AreEqual ("c", constant.Name);
+ Assert.AreEqual ((decimal) 74, constant.Value);
+ Assert.AreEqual (MetadataType.ValueType, constant.ConstantType.MetadataType);
+
+ method = type.GetMethod ("Foo");
+ debug_info = method.DebugInformation;
+
+ Assert.IsNotNull (debug_info.Scope);
+ Assert.IsTrue (debug_info.Scope.HasConstants);
+ Assert.AreEqual (4, debug_info.Scope.Constants.Count);
+
+ constant = debug_info.Scope.Constants [0];
+ Assert.AreEqual ("s", constant.Name);
+ Assert.AreEqual ("const string", constant.Value);
+ Assert.AreEqual (MetadataType.String, constant.ConstantType.MetadataType);
+
+ constant = debug_info.Scope.Constants [1];
+ Assert.AreEqual ("f", constant.Name);
+ Assert.AreEqual (1, constant.Value);
+ Assert.AreEqual (MetadataType.Int32, constant.ConstantType.MetadataType);
+
+ constant = debug_info.Scope.Constants [2];
+ Assert.AreEqual ("o", constant.Name);
+ Assert.AreEqual (null, constant.Value);
+ Assert.AreEqual (MetadataType.Object, constant.ConstantType.MetadataType);
+
+ constant = debug_info.Scope.Constants [3];
+ Assert.AreEqual ("u", constant.Name);
+ Assert.AreEqual (null, constant.Value);
+ Assert.AreEqual (MetadataType.String, constant.ConstantType.MetadataType);
+ }, readOnly: Platform.OnMono, symbolReaderProvider: typeof (PdbReaderProvider), symbolWriterProvider: typeof (PdbWriterProvider));
+ }
+
+ [Test]
+ public void ImportScope ()
+ {
+ TestModule ("ComplexPdb.dll", module => {
+ var type = module.GetType ("ComplexPdb.Program");
+ var method = type.GetMethod ("Bar");
+ var debug_info = method.DebugInformation;
+
+ Assert.IsNotNull (debug_info.Scope);
+
+ var import = debug_info.Scope.Import;
+ Assert.IsNotNull (import);
+
+ Assert.IsTrue (import.HasTargets);
+ Assert.AreEqual (6, import.Targets.Count);
+ var target = import.Targets [0];
+
+ Assert.AreEqual (ImportTargetKind.ImportNamespace, target.Kind);
+ Assert.AreEqual ("System", target.Namespace);
+
+ target = import.Targets [1];
+
+ Assert.AreEqual (ImportTargetKind.ImportNamespace, target.Kind);
+ Assert.AreEqual ("System.Collections.Generic", target.Namespace);
+
+ target = import.Targets [2];
+
+ Assert.AreEqual (ImportTargetKind.ImportNamespace, target.Kind);
+ Assert.AreEqual ("System.Threading.Tasks", target.Namespace);
+
+ target = import.Targets [3];
+
+ Assert.AreEqual (ImportTargetKind.ImportType, target.Kind);
+ Assert.AreEqual ("System.Console", target.Type.FullName);
+
+ target = import.Targets [4];
+
+ Assert.AreEqual (ImportTargetKind.DefineTypeAlias, target.Kind);
+ Assert.AreEqual ("Foo1", target.Alias);
+ Assert.AreEqual ("System.Console", target.Type.FullName);
+
+ target = import.Targets [5];
+
+ Assert.AreEqual (ImportTargetKind.DefineNamespaceAlias, target.Kind);
+ Assert.AreEqual ("Foo2", target.Alias);
+ Assert.AreEqual ("System.Reflection", target.Namespace);
+ }, readOnly: Platform.OnMono, symbolReaderProvider: typeof (PdbReaderProvider), symbolWriterProvider: typeof (PdbWriterProvider));
+ }
+
+ [Test]
+ public void StateMachineKickOff ()
+ {
+ TestModule ("ComplexPdb.dll", module => {
+ var state_machine = module.GetType ("ComplexPdb.Program/<TestAsync>d__2");
+ var move_next = state_machine.GetMethod ("MoveNext");
+ var symbol = move_next.DebugInformation;
+
+ Assert.IsNotNull (symbol);
+ Assert.IsNotNull (symbol.StateMachineKickOffMethod);
+ Assert.AreEqual ("System.Threading.Tasks.Task ComplexPdb.Program::TestAsync()", symbol.StateMachineKickOffMethod.FullName);
+ }, readOnly: Platform.OnMono, symbolReaderProvider: typeof (PdbReaderProvider), symbolWriterProvider: typeof (PdbWriterProvider));
+ }
+
+ [Test]
+ public void Iterators ()
+ {
+ TestModule ("ComplexPdb.dll", module => {
+ var state_machine = module.GetType ("ComplexPdb.Program/<TestAsync>d__2");
+ var move_next = state_machine.GetMethod ("MoveNext");
+
+ Assert.IsTrue (move_next.DebugInformation.HasCustomDebugInformations);
+ Assert.AreEqual (2, move_next.DebugInformation.CustomDebugInformations.Count);
+
+ var state_machine_scope = move_next.DebugInformation.CustomDebugInformations [0] as StateMachineScopeDebugInformation;
+ Assert.IsNotNull (state_machine_scope);
+ Assert.AreEqual (142, state_machine_scope.Start.Offset);
+ Assert.AreEqual (319, state_machine_scope.End.Offset);
+
+ var async_body = move_next.DebugInformation.CustomDebugInformations [1] as AsyncMethodBodyDebugInformation;
+ Assert.IsNotNull (async_body);
+ Assert.AreEqual (-1, async_body.CatchHandler.Offset);
+
+ Assert.AreEqual (2, async_body.Yields.Count);
+ Assert.AreEqual (68, async_body.Yields [0].Offset);
+ Assert.AreEqual (197, async_body.Yields [1].Offset);
+
+ Assert.AreEqual (2, async_body.Resumes.Count);
+ Assert.AreEqual (98, async_body.Resumes [0].Offset);
+ Assert.AreEqual (227, async_body.Resumes [1].Offset);
+
+ Assert.AreEqual (move_next, async_body.MoveNextMethod);
+ }, readOnly: Platform.OnMono, symbolReaderProvider: typeof (PdbReaderProvider), symbolWriterProvider: typeof (PdbWriterProvider));
+ }
+
+ [Test]
public void CreateMethodFromScratch ()
{
IgnoreOnMono ();
diff --git a/symbols/pdb/Test/Resources/assemblies/ComplexPdb.cs b/symbols/pdb/Test/Resources/assemblies/ComplexPdb.cs
new file mode 100644
index 0000000..ae29775
--- /dev/null
+++ b/symbols/pdb/Test/Resources/assemblies/ComplexPdb.cs
@@ -0,0 +1,71 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using static System.Console;
+using Foo1 = System.Console;
+using Foo2 = System.Reflection;
+
+namespace ComplexPdb
+{
+ public class Program
+ {
+ private static void Foo()
+ {
+ const string s = "const string";
+ const int f = 1;
+ const object o = null;
+ const string u = null;
+ WriteLine(s);
+ WriteLine(2);
+ }
+
+ private static void Bar(int i)
+ {
+ int result;
+ if (i < 0)
+ {
+ int s = 1;
+ result = s;
+ }
+ else
+ {
+ const int b = 12;
+ const decimal c = 74;
+ int s = -1;
+ result = s + b + (int)c;
+ if (result > b)
+ {
+ int u = result * b;
+ Console.WriteLine(u);
+ }
+ }
+ WriteLine(result);
+ }
+
+ public async Task TestAsync()
+ {
+ WriteLine("Hello1");
+ await Task.Delay(100);
+
+ for (int i = 0; i < 4; ++i)
+ {
+ WriteLine("Hello2");
+ await Task.Delay(100);
+ WriteLine("Hello3");
+ }
+ }
+
+ public IEnumerable<string> TestIterator()
+ {
+ WriteLine("Hello1");
+ yield return "Hello1";
+
+ for (int i = 0; i < 4; ++i)
+ {
+ WriteLine("Hello1");
+ yield return "Hello2";
+ WriteLine("Hello3");
+ }
+ }
+ }
+}
diff --git a/symbols/pdb/Test/Resources/assemblies/ComplexPdb.dll b/symbols/pdb/Test/Resources/assemblies/ComplexPdb.dll
new file mode 100644
index 0000000..353e806
--- /dev/null
+++ b/symbols/pdb/Test/Resources/assemblies/ComplexPdb.dll
Binary files differ
diff --git a/symbols/pdb/Test/Resources/assemblies/ComplexPdb.pdb b/symbols/pdb/Test/Resources/assemblies/ComplexPdb.pdb
new file mode 100644
index 0000000..0aef0e3
--- /dev/null
+++ b/symbols/pdb/Test/Resources/assemblies/ComplexPdb.pdb
Binary files differ