diff options
author | Marek Safar <marek.safar@gmail.com> | 2017-06-10 08:51:30 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-06-10 08:51:30 +0300 |
commit | 7b40eb15610b8cf809e9bc03c08ad2f7fe8b6e4f (patch) | |
tree | 50b78e3c793ba2aa91c3296f1f556a2839d1bf79 | |
parent | f64903c0e069224aaac7de243fa0a3b17684b4dd (diff) | |
parent | 44611fa61f6974d8b6bdcff24fed6f28ec9a1265 (diff) |
Merge pull request #14 from jbevain/master
Update Cecil
-rw-r--r-- | Mono.Cecil.Cil/PortablePdb.cs | 22 | ||||
-rw-r--r-- | Mono.Cecil.Cil/Symbols.cs | 53 | ||||
-rw-r--r-- | Mono.Cecil/AssemblyReader.cs | 42 | ||||
-rw-r--r-- | Mono.Cecil/AssemblyWriter.cs | 45 | ||||
-rw-r--r-- | Mono.Cecil/ModuleDefinition.cs | 20 | ||||
-rw-r--r-- | Test/Mono.Cecil.Tests/BaseTestFixture.cs | 2 | ||||
-rw-r--r-- | Test/Mono.Cecil.Tests/PortablePdbTests.cs | 110 | ||||
-rw-r--r-- | Test/Resources/assemblies/TargetLib.dll | bin | 0 -> 4096 bytes | |||
-rw-r--r-- | Test/Resources/assemblies/TargetLib.pdb | bin | 0 -> 420 bytes | |||
-rw-r--r-- | Test/Resources/assemblies/embedcs.exe | bin | 0 -> 4096 bytes | |||
-rw-r--r-- | Test/Resources/assemblies/embedcs.pdb | bin | 0 -> 924 bytes | |||
-rw-r--r-- | symbols/pdb/Mono.Cecil.Pdb/NativePdbReader.cs | 3 | ||||
-rw-r--r-- | symbols/pdb/Mono.Cecil.Pdb/NativePdbWriter.cs | 4 | ||||
-rw-r--r-- | symbols/pdb/Test/Mono.Cecil.Tests/PdbTests.cs | 7 | ||||
-rw-r--r-- | symbols/pdb/Test/Resources/assemblies/EmptyRootNamespace.dll | bin | 0 -> 7168 bytes | |||
-rw-r--r-- | symbols/pdb/Test/Resources/assemblies/EmptyRootNamespace.pdb | bin | 0 -> 19968 bytes |
16 files changed, 299 insertions, 9 deletions
diff --git a/Mono.Cecil.Cil/PortablePdb.cs b/Mono.Cecil.Cil/PortablePdb.cs index eb124d7..717249e 100644 --- a/Mono.Cecil.Cil/PortablePdb.cs +++ b/Mono.Cecil.Cil/PortablePdb.cs @@ -94,7 +94,11 @@ namespace Mono.Cecil.Cil { var pdb_guid = new Guid (buffer); - return module_guid == pdb_guid; + if (module_guid != pdb_guid) + return false; + + ReadModule (); + return true; } static int ReadInt32 (byte [] bytes, int start) @@ -105,6 +109,11 @@ namespace Mono.Cecil.Cil { | (bytes [start + 3] << 24)); } + void ReadModule () + { + module.custom_infos = debug_reader.GetCustomDebugInformation (module); + } + public MethodDebugInformation Read (MethodDefinition method) { var info = new MethodDebugInformation (method); @@ -247,6 +256,7 @@ namespace Mono.Cecil.Cil { interface IMetadataSymbolWriter : ISymbolWriter { void SetMetadata (MetadataBuilder metadata); + void WriteModule (); } public sealed class PortablePdbWriter : ISymbolWriter, IMetadataSymbolWriter { @@ -279,6 +289,11 @@ namespace Mono.Cecil.Cil { this.pdb_metadata.metadata_builder = metadata; } + void IMetadataSymbolWriter.WriteModule () + { + pdb_metadata.AddCustomDebugInformations (module); + } + public ISymbolReaderProvider GetReaderProvider () { return new PortablePdbReaderProvider (); @@ -474,6 +489,11 @@ namespace Mono.Cecil.Cil { { ((IMetadataSymbolWriter) writer).SetMetadata (metadata); } + + void IMetadataSymbolWriter.WriteModule () + { + ((IMetadataSymbolWriter) writer).WriteModule (); + } } #endif diff --git a/Mono.Cecil.Cil/Symbols.cs b/Mono.Cecil.Cil/Symbols.cs index 6b13c74..ed3f1ef 100644 --- a/Mono.Cecil.Cil/Symbols.cs +++ b/Mono.Cecil.Cil/Symbols.cs @@ -433,6 +433,8 @@ namespace Mono.Cecil.Cil { DynamicVariable, DefaultNamespace, AsyncMethodBody, + EmbeddedSource, + SourceLink, } public abstract class CustomDebugInformation : DebugInformation { @@ -558,6 +560,57 @@ namespace Mono.Cecil.Cil { } } + public sealed class EmbeddedSourceDebugInformation : CustomDebugInformation { + + internal byte [] content; + internal bool compress; + + public byte [] Content { + get { return content; } + set { content = value; } + } + + public bool Compress { + get { return compress; } + set { compress = value; } + } + + public override CustomDebugInformationKind Kind { + get { return CustomDebugInformationKind.EmbeddedSource; } + } + + public static Guid KindIdentifier = new Guid ("{0E8A571B-6926-466E-B4AD-8AB04611F5FE}"); + + public EmbeddedSourceDebugInformation (byte [] content, bool compress) + : base (KindIdentifier) + { + this.content = content; + this.compress = compress; + } + } + + public sealed class SourceLinkDebugInformation : CustomDebugInformation { + + internal string content; + + public string Content { + get { return content; } + set { content = value; } + } + + public override CustomDebugInformationKind Kind { + get { return CustomDebugInformationKind.SourceLink; } + } + + public static Guid KindIdentifier = new Guid ("{CC110556-A091-4D38-9FEC-25AB9A351A6A}"); + + public SourceLinkDebugInformation (string content) + : base (KindIdentifier) + { + this.content = content; + } + } + public sealed class MethodDebugInformation : DebugInformation { internal MethodDefinition method; diff --git a/Mono.Cecil/AssemblyReader.cs b/Mono.Cecil/AssemblyReader.cs index 654bf48..8217bc0 100644 --- a/Mono.Cecil/AssemblyReader.cs +++ b/Mono.Cecil/AssemblyReader.cs @@ -11,6 +11,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.IO.Compression; using System.Text; using Mono.Collections.Generic; @@ -2856,12 +2857,22 @@ namespace Mono.Cecil { if (signature == 0) return new Collection<SequencePoint> (0); - var document = metadata.GetDocument (document_index); + var document = GetDocument (document_index); var reader = ReadSignature (signature); return reader.ReadSequencePoints (document); } + public Document GetDocument (uint rid) + { + var document = metadata.GetDocument (rid); + if (document == null) + return null; + + document.custom_infos = GetCustomDebugInformation (document); + return document; + } + void InitializeLocalScopes () { if (metadata.LocalScopes != null) @@ -3187,6 +3198,31 @@ namespace Mono.Cecil { async_body.move_next = GetMethodDefinition (move_next_rid); infos.Add (async_body); + } else if (rows [i].Col1 == EmbeddedSourceDebugInformation.KindIdentifier) { + var signature = ReadSignature (rows [i].Col2); + var format = signature.ReadInt32 (); + var length = signature.sig_length - 4; + + var info = null as CustomDebugInformation; + + if (format == 0) { + info = new EmbeddedSourceDebugInformation (signature.ReadBytes ((int) length), compress: false); + } else if (format > 0) { + var compressed_stream = new MemoryStream (signature.ReadBytes ((int) length)); + var decompressed_document = new byte [format]; // if positive, format is the decompressed length of the document + var decompressed_stream = new MemoryStream (decompressed_document); + + using (var deflate_stream = new DeflateStream (compressed_stream, CompressionMode.Decompress, leaveOpen: true)) + deflate_stream.CopyTo (decompressed_stream); + + info = new EmbeddedSourceDebugInformation (decompressed_document, compress: true); + } else if (format < 0) { + info = new BinaryCustomDebugInformation (rows [i].Col1, ReadBlob (rows [i].Col2)); + } + + infos.Add (info); + } else if (rows [i].Col1 == SourceLinkDebugInformation.KindIdentifier) { + infos.Add (new SourceLinkDebugInformation (Encoding.UTF8.GetString (ReadBlob (rows [i].Col2)))); } else { infos.Add (new BinaryCustomDebugInformation (rows [i].Col1, ReadBlob (rows [i].Col2))); } @@ -3759,7 +3795,7 @@ namespace Mono.Cecil { ReadCompressedUInt32 (); // local_sig_token if (document == null) - document = reader.metadata.GetDocument (ReadCompressedUInt32 ()); + document = reader.GetDocument (ReadCompressedUInt32 ()); var offset = 0; var start_line = 0; @@ -3769,7 +3805,7 @@ namespace Mono.Cecil { for (var i = 0; CanReadMore (); i++) { var delta_il = (int) ReadCompressedUInt32 (); if (i > 0 && delta_il == 0) { - document = reader.metadata.GetDocument (ReadCompressedUInt32 ()); + document = reader.GetDocument (ReadCompressedUInt32 ()); continue; } diff --git a/Mono.Cecil/AssemblyWriter.cs b/Mono.Cecil/AssemblyWriter.cs index f1423f4..e5003b8 100644 --- a/Mono.Cecil/AssemblyWriter.cs +++ b/Mono.Cecil/AssemblyWriter.cs @@ -11,6 +11,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.IO.Compression; using System.Text; using Mono; @@ -1044,6 +1045,10 @@ namespace Mono.Cecil { if (module.EntryPoint != null) entry_point = LookupToken (module.EntryPoint); + + var pdb_writer = symbol_writer as IMetadataSymbolWriter; + if (pdb_writer != null) + pdb_writer.WriteModule (); } void BuildAssembly () @@ -2345,7 +2350,7 @@ namespace Mono.Cecil { return signature; } - void AddCustomDebugInformations (ICustomDebugInformationProvider provider) + public void AddCustomDebugInformations (ICustomDebugInformationProvider provider) { if (!provider.HasCustomDebugInformations) return; @@ -2365,6 +2370,12 @@ namespace Mono.Cecil { case CustomDebugInformationKind.StateMachineScope: AddStateMachineScopeDebugInformation (provider, (StateMachineScopeDebugInformation) custom_info); break; + case CustomDebugInformationKind.EmbeddedSource: + AddEmbeddedSourceDebugInformation (provider, (EmbeddedSourceDebugInformation) custom_info); + break; + case CustomDebugInformationKind.SourceLink: + AddSourceLinkDebugInformation (provider, (SourceLinkDebugInformation) custom_info); + break; default: throw new NotImplementedException (); } @@ -2401,6 +2412,36 @@ namespace Mono.Cecil { AddCustomDebugInformation (provider, async_method, signature); } + void AddEmbeddedSourceDebugInformation (ICustomDebugInformationProvider provider, EmbeddedSourceDebugInformation embedded_source) + { + var signature = CreateSignatureWriter (); + var content = embedded_source.content ?? Empty<byte>.Array; + if (embedded_source.compress) { + signature.WriteInt32 (content.Length); + + var decompressed_stream = new MemoryStream (content); + var content_stream = new MemoryStream (); + + using (var compress_stream = new DeflateStream (content_stream, CompressionMode.Compress, leaveOpen: true)) + decompressed_stream.CopyTo (compress_stream); + + signature.WriteBytes (content_stream.ToArray ()); + } else { + signature.WriteInt32 (0); + signature.WriteBytes (content); + } + + AddCustomDebugInformation (provider, embedded_source, signature); + } + + void AddSourceLinkDebugInformation (ICustomDebugInformationProvider provider, SourceLinkDebugInformation source_link) + { + var signature = CreateSignatureWriter (); + signature.WriteBytes (Encoding.UTF8.GetBytes (source_link.content)); + + AddCustomDebugInformation (provider, source_link, signature); + } + void AddCustomDebugInformation (ICustomDebugInformationProvider provider, CustomDebugInformation custom_info, SignatureWriter signature) { AddCustomDebugInformation (provider, custom_info, GetBlobIndex (signature)); @@ -2505,6 +2546,8 @@ namespace Mono.Cecil { document.token = token; + AddCustomDebugInformations (document); + document_map.Add (document.Url, token); return token; diff --git a/Mono.Cecil/ModuleDefinition.cs b/Mono.Cecil/ModuleDefinition.cs index c8d055f..4550537 100644 --- a/Mono.Cecil/ModuleDefinition.cs +++ b/Mono.Cecil/ModuleDefinition.cs @@ -254,7 +254,7 @@ namespace Mono.Cecil { #endif - public sealed class ModuleDefinition : ModuleReference, ICustomAttributeProvider, IDisposable { + public sealed class ModuleDefinition : ModuleReference, ICustomAttributeProvider, ICustomDebugInformationProvider, IDisposable { internal Image Image; internal MetadataSystem MetadataSystem; @@ -294,6 +294,8 @@ namespace Mono.Cecil { Collection<ExportedType> exported_types; TypeDefinitionCollection types; + internal Collection<CustomDebugInformation> custom_infos; + public bool IsMain { get { return kind != ModuleKind.NetModule; } } @@ -580,6 +582,18 @@ namespace Mono.Cecil { set { entry_point = value; } } + public bool HasCustomDebugInformations { + get { + return custom_infos != null && custom_infos.Count > 0; + } + } + + public Collection<CustomDebugInformation> CustomDebugInformations { + get { + return custom_infos ?? (custom_infos = new Collection<CustomDebugInformation> ()); + } + } + internal ModuleDefinition () { this.MetadataSystem = new MetadataSystem (); @@ -1237,13 +1251,13 @@ namespace Mono.Cecil { public static void CheckWriteSeek (Stream stream) { if (!stream.CanWrite || !stream.CanSeek) - throw new ArgumentException (); + throw new ArgumentException ("Stream must be writable and seekable."); } public static void CheckReadSeek (Stream stream) { if (!stream.CanRead || !stream.CanSeek) - throw new ArgumentException (); + throw new ArgumentException ("Stream must be readable and seekable."); } public static void CheckType (object type) diff --git a/Test/Mono.Cecil.Tests/BaseTestFixture.cs b/Test/Mono.Cecil.Tests/BaseTestFixture.cs index ee9d521..c49880e 100644 --- a/Test/Mono.Cecil.Tests/BaseTestFixture.cs +++ b/Test/Mono.Cecil.Tests/BaseTestFixture.cs @@ -87,7 +87,7 @@ namespace Mono.Cecil.Tests { Assert.AreEqual (Normalize (expected), Normalize (Formatter.FormatMethodBody (method))); } - static string Normalize (string str) + public static string Normalize (string str) { return str.Trim ().Replace ("\r\n", "\n"); } diff --git a/Test/Mono.Cecil.Tests/PortablePdbTests.cs b/Test/Mono.Cecil.Tests/PortablePdbTests.cs index 759677c..3e1634e 100644 --- a/Test/Mono.Cecil.Tests/PortablePdbTests.cs +++ b/Test/Mono.Cecil.Tests/PortablePdbTests.cs @@ -2,6 +2,7 @@ using System; using System.IO; using System.Linq; +using System.Text; using NUnit.Framework; using Mono.Cecil.Cil; @@ -406,6 +407,115 @@ namespace Mono.Cecil.Tests { } [Test] + public void SourceLink () + { + TestModule ("TargetLib.dll", module => { + Assert.IsTrue (module.HasCustomDebugInformations); + Assert.AreEqual (1, module.CustomDebugInformations.Count); + + var source_link = module.CustomDebugInformations [0] as SourceLinkDebugInformation; + Assert.IsNotNull (source_link); + Assert.AreEqual ("{\"documents\":{\"C:\\\\tmp\\\\SourceLinkProblem\\\\*\":\"https://raw.githubusercontent.com/bording/SourceLinkProblem/197d965ee7f1e7f8bd3cea55b5f904aeeb8cd51e/*\"}}", source_link.Content); + }, symbolReaderProvider: typeof (PortablePdbReaderProvider), symbolWriterProvider: typeof (PortablePdbWriterProvider)); + } + + [Test] + public void EmbeddedSource () + { + TestModule ("embedcs.exe", module => { + var program = GetDocument (module.GetType ("Program")); + var program_src = GetSourceDebugInfo (program); + Assert.IsTrue (program_src.compress); + var program_src_content = Encoding.UTF8.GetString (program_src.Content); + Assert.AreEqual (Normalize (@"using System; + +class Program +{ + static void Main() + { + // Hello hello hello hello hello hello + // Hello hello hello hello hello hello + // Hello hello hello hello hello hello + // Hello hello hello hello hello hello + // Hello hello hello hello hello hello + // Hello hello hello hello hello hello + // Hello hello hello hello hello hello + // Hello hello hello hello hello hello + // Hello hello hello hello hello hello + // Hello hello hello hello hello hello + // Hello hello hello hello hello hello + // Hello hello hello hello hello hello + // Hello hello hello hello hello hello + // Hello hello hello hello hello hello + // Hello hello hello hello hello hello + // Hello hello hello hello hello hello + // Hello hello hello hello hello hello + // Hello hello hello hello hello hello + // Hello hello hello hello hello hello + // Hello hello hello hello hello hello + // Hello hello hello hello hello hello + // Hello hello hello hello hello hello + // Hello hello hello hello hello hello + // Hello hello hello hello hello hello + Console.WriteLine(B.Do()); + Console.WriteLine(A.Do()); + } +} +"), Normalize (program_src_content)); + + var a = GetDocument (module.GetType ("A")); + var a_src = GetSourceDebugInfo (a); + Assert.IsFalse (a_src.compress); + var a_src_content = Encoding.UTF8.GetString (a_src.Content); + Assert.AreEqual (Normalize (@"class A +{ + public static string Do() + { + return ""A::Do""; + } +}"), Normalize (a_src_content)); + + var b = GetDocument(module.GetType ("B")); + var b_src = GetSourceDebugInfo (b); + Assert.IsFalse (b_src.compress); + var b_src_content = Encoding.UTF8.GetString (b_src.Content); + Assert.AreEqual (Normalize (@"class B +{ + public static string Do() + { + return ""B::Do""; + } +}"), Normalize (b_src_content)); + }, symbolReaderProvider: typeof (PortablePdbReaderProvider), symbolWriterProvider: typeof (PortablePdbWriterProvider)); + } + + static Document GetDocument (TypeDefinition type) + { + foreach (var method in type.Methods) { + if (!method.HasBody) + continue; + + foreach (var instruction in method.Body.Instructions) { + var sp = method.DebugInformation.GetSequencePoint (instruction); + if (sp != null && sp.Document != null) + return sp.Document; + } + } + + return null; + } + + static EmbeddedSourceDebugInformation GetSourceDebugInfo (Document document) + { + Assert.IsTrue (document.HasCustomDebugInformations); + Assert.AreEqual (1, document.CustomDebugInformations.Count); + + var source = document.CustomDebugInformations [0] as EmbeddedSourceDebugInformation; + Assert.IsNotNull (source); + return source; + } + + [Test] public void PortablePdbLineInfo () { TestModule ("line.exe", module => { diff --git a/Test/Resources/assemblies/TargetLib.dll b/Test/Resources/assemblies/TargetLib.dll Binary files differnew file mode 100644 index 0000000..e960d44 --- /dev/null +++ b/Test/Resources/assemblies/TargetLib.dll diff --git a/Test/Resources/assemblies/TargetLib.pdb b/Test/Resources/assemblies/TargetLib.pdb Binary files differnew file mode 100644 index 0000000..730d74c --- /dev/null +++ b/Test/Resources/assemblies/TargetLib.pdb diff --git a/Test/Resources/assemblies/embedcs.exe b/Test/Resources/assemblies/embedcs.exe Binary files differnew file mode 100644 index 0000000..2681642 --- /dev/null +++ b/Test/Resources/assemblies/embedcs.exe diff --git a/Test/Resources/assemblies/embedcs.pdb b/Test/Resources/assemblies/embedcs.pdb Binary files differnew file mode 100644 index 0000000..78294d1 --- /dev/null +++ b/Test/Resources/assemblies/embedcs.pdb diff --git a/symbols/pdb/Mono.Cecil.Pdb/NativePdbReader.cs b/symbols/pdb/Mono.Cecil.Pdb/NativePdbReader.cs index d4b45ed..b07191d 100644 --- a/symbols/pdb/Mono.Cecil.Pdb/NativePdbReader.cs +++ b/symbols/pdb/Mono.Cecil.Pdb/NativePdbReader.cs @@ -264,6 +264,9 @@ namespace Mono.Cecil.Pdb { var import = new ImportDebugInformation (); foreach (var used_namespace in scope.usedNamespaces) { + if (string.IsNullOrEmpty (used_namespace)) + continue; + ImportTarget target = null; var value = used_namespace.Substring (1); switch (used_namespace [0]) { diff --git a/symbols/pdb/Mono.Cecil.Pdb/NativePdbWriter.cs b/symbols/pdb/Mono.Cecil.Pdb/NativePdbWriter.cs index 1c681ca..e3d6d17 100644 --- a/symbols/pdb/Mono.Cecil.Pdb/NativePdbWriter.cs +++ b/symbols/pdb/Mono.Cecil.Pdb/NativePdbWriter.cs @@ -80,6 +80,10 @@ namespace Mono.Cecil.Pdb { this.metadata = metadata; } + void IMetadataSymbolWriter.WriteModule () + { + } + void DefineCustomMetadata (MethodDebugInformation info, MetadataToken import_parent) { var metadata = new CustomMetadataWriter (this.writer); diff --git a/symbols/pdb/Test/Mono.Cecil.Tests/PdbTests.cs b/symbols/pdb/Test/Mono.Cecil.Tests/PdbTests.cs index 10b5639..054f1f8 100644 --- a/symbols/pdb/Test/Mono.Cecil.Tests/PdbTests.cs +++ b/symbols/pdb/Test/Mono.Cecil.Tests/PdbTests.cs @@ -154,6 +154,13 @@ namespace Mono.Cecil.Tests { } [Test] + public void EmptyRootNamespace () + { + TestModule ("EmptyRootNamespace.dll", module => { + }, readOnly: Platform.OnMono, symbolReaderProvider: typeof(PdbReaderProvider), symbolWriterProvider: typeof(PdbWriterProvider)); + } + + [Test] public void LocalVariables () { TestModule ("ComplexPdb.dll", module => { diff --git a/symbols/pdb/Test/Resources/assemblies/EmptyRootNamespace.dll b/symbols/pdb/Test/Resources/assemblies/EmptyRootNamespace.dll Binary files differnew file mode 100644 index 0000000..7992af6 --- /dev/null +++ b/symbols/pdb/Test/Resources/assemblies/EmptyRootNamespace.dll diff --git a/symbols/pdb/Test/Resources/assemblies/EmptyRootNamespace.pdb b/symbols/pdb/Test/Resources/assemblies/EmptyRootNamespace.pdb Binary files differnew file mode 100644 index 0000000..9550ece --- /dev/null +++ b/symbols/pdb/Test/Resources/assemblies/EmptyRootNamespace.pdb |