Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove internal IMetadataSymbolWriter that prevents external composition of symbol writers #564

Merged
merged 2 commits into from
Jan 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 13 additions & 34 deletions Mono.Cecil.Cil/PortablePdb.cs
Original file line number Diff line number Diff line change
Expand Up @@ -253,12 +253,7 @@ ISymbolWriter GetSymbolWriter (ModuleDefinition module, Disposable<Stream> strea
}
}

interface IMetadataSymbolWriter : ISymbolWriter {
void SetMetadata (MetadataBuilder metadata);
void WriteModule ();
}

public sealed class PortablePdbWriter : ISymbolWriter, IMetadataSymbolWriter {
public sealed class PortablePdbWriter : ISymbolWriter {

readonly MetadataBuilder pdb_metadata;
readonly ModuleDefinition module;
Expand All @@ -272,25 +267,19 @@ internal PortablePdbWriter (MetadataBuilder pdb_metadata, ModuleDefinition modul
{
this.pdb_metadata = pdb_metadata;
this.module = module;
}

internal PortablePdbWriter (MetadataBuilder pdb_metadata, ModuleDefinition module, ImageWriter writer)
: this (pdb_metadata, module)
{
this.writer = writer;
}

void IMetadataSymbolWriter.SetMetadata (MetadataBuilder metadata)
{
this.module_metadata = metadata;
this.module_metadata = module.metadata_builder;

if (module_metadata != pdb_metadata)
this.pdb_metadata.metadata_builder = metadata;
this.pdb_metadata.metadata_builder = this.module_metadata;

pdb_metadata.AddCustomDebugInformations (module);
}

void IMetadataSymbolWriter.WriteModule ()
internal PortablePdbWriter (MetadataBuilder pdb_metadata, ModuleDefinition module, ImageWriter writer)
: this (pdb_metadata, module)
{
pdb_metadata.AddCustomDebugInformations (module);
this.writer = writer;
}

public ISymbolReaderProvider GetReaderProvider ()
Expand Down Expand Up @@ -318,11 +307,11 @@ public ImageDebugHeader GetDebugHeader ()
// PDB Age
buffer.WriteUInt32 (1);
// PDB Path
var filename = writer.BaseStream.GetFileName ();
if (!string.IsNullOrEmpty (filename))
filename = Path.GetFileName (filename);
var filename = writer.BaseStream.GetFileName();
if (!string.IsNullOrEmpty(filename))
filename = Path.GetFileName(filename);

buffer.WriteBytes (System.Text.Encoding.UTF8.GetBytes (filename));
buffer.WriteBytes(System.Text.Encoding.UTF8.GetBytes(filename));
buffer.WriteByte (0);

var data = new byte [buffer.length];
Expand Down Expand Up @@ -428,7 +417,7 @@ public ISymbolWriter GetSymbolWriter (ModuleDefinition module, Stream symbolStre
}
}

public sealed class EmbeddedPortablePdbWriter : ISymbolWriter, IMetadataSymbolWriter {
public sealed class EmbeddedPortablePdbWriter : ISymbolWriter {

readonly Stream stream;
readonly PortablePdbWriter writer;
Expand Down Expand Up @@ -485,16 +474,6 @@ public void Write (MethodDebugInformation info)
public void Dispose ()
{
}

void IMetadataSymbolWriter.SetMetadata (MetadataBuilder metadata)
{
((IMetadataSymbolWriter) writer).SetMetadata (metadata);
}

void IMetadataSymbolWriter.WriteModule ()
{
((IMetadataSymbolWriter) writer).WriteModule ();
}
}

#endif
Expand Down
57 changes: 25 additions & 32 deletions Mono.Cecil/AssemblyWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,18 +110,25 @@ static void Write (ModuleDefinition module, Disposable<Stream> stream, WriterPar
}
#endif

using (var symbol_writer = GetSymbolWriter (module, fq_name, symbol_writer_provider, parameters)) {
var metadata = new MetadataBuilder (module, fq_name, timestamp, symbol_writer_provider, symbol_writer);
BuildMetadata (module, metadata);
var metadata = new MetadataBuilder (module, fq_name, timestamp, symbol_writer_provider);
try {
module.metadata_builder = metadata;

var writer = ImageWriter.CreateWriter (module, metadata, stream);
stream.value.SetLength (0);
writer.WriteImage ();
using (var symbol_writer = GetSymbolWriter (module, fq_name, symbol_writer_provider, parameters)) {
metadata.SetSymbolWriter (symbol_writer);
BuildMetadata (module, metadata);

var writer = ImageWriter.CreateWriter (module, metadata, stream);
stream.value.SetLength (0);
writer.WriteImage ();

#if !NET_CORE
if (parameters.StrongNameKeyPair != null)
CryptoService.StrongName (stream.value, writer, parameters.StrongNameKeyPair);
if (parameters.StrongNameKeyPair != null)
CryptoService.StrongName (stream.value, writer, parameters.StrongNameKeyPair);
#endif
}
} finally {
module.metadata_builder = null;
}
}

Expand Down Expand Up @@ -796,7 +803,7 @@ sealed class MetadataBuilder {

readonly internal ModuleDefinition module;
readonly internal ISymbolWriterProvider symbol_writer_provider;
readonly internal ISymbolWriter symbol_writer;
internal ISymbolWriter symbol_writer;
readonly internal TextMap text_map;
readonly internal string fq_name;
readonly internal uint timestamp;
Expand Down Expand Up @@ -846,8 +853,6 @@ sealed class MetadataBuilder {
readonly TypeSpecTable typespec_table;
readonly MethodSpecTable method_spec_table;

readonly bool portable_pdb;

internal MetadataBuilder metadata_builder;

readonly DocumentTable document_table;
Expand All @@ -862,26 +867,14 @@ sealed class MetadataBuilder {
readonly Dictionary<ImportScopeRow, MetadataToken> import_scope_map;
readonly Dictionary<string, MetadataToken> document_map;

public MetadataBuilder (ModuleDefinition module, string fq_name, uint timestamp, ISymbolWriterProvider symbol_writer_provider, ISymbolWriter symbol_writer)
public MetadataBuilder (ModuleDefinition module, string fq_name, uint timestamp, ISymbolWriterProvider symbol_writer_provider)
{
this.module = module;
this.text_map = CreateTextMap ();
this.fq_name = fq_name;
this.timestamp = timestamp;
this.symbol_writer_provider = symbol_writer_provider;

if (symbol_writer == null && module.HasImage && module.Image.HasDebugTables ()) {
symbol_writer = new PortablePdbWriter (this, module);
}

this.symbol_writer = symbol_writer;

var pdb_writer = symbol_writer as IMetadataSymbolWriter;
if (pdb_writer != null) {
portable_pdb = true;
pdb_writer.SetMetadata (this);
}

this.code = new CodeWriter (this);
this.data = new DataBuffer ();
this.resources = new ResourceBuffer ();
Expand Down Expand Up @@ -916,9 +909,6 @@ public MetadataBuilder (ModuleDefinition module, string fq_name, uint timestamp,
method_spec_map = new Dictionary<MethodSpecRow, MetadataToken> (row_equality_comparer);
generic_parameters = new Collection<GenericParameter> ();

if (!portable_pdb)
return;

this.document_table = GetTable<DocumentTable> (Table.Document);
this.method_debug_information_table = GetTable<MethodDebugInformationTable> (Table.MethodDebugInformation);
this.local_scope_table = GetTable<LocalScopeTable> (Table.LocalScope);
Expand All @@ -937,7 +927,6 @@ public MetadataBuilder (ModuleDefinition module, PortablePdbWriterProvider write
this.module = module;
this.text_map = new TextMap ();
this.symbol_writer_provider = writer_provider;
this.portable_pdb = true;

this.string_heap = new StringHeapBuffer ();
this.guid_heap = new GuidHeapBuffer ();
Expand All @@ -961,6 +950,14 @@ public MetadataBuilder (ModuleDefinition module, PortablePdbWriterProvider write
this.import_scope_map = new Dictionary<ImportScopeRow, MetadataToken> (row_equality_comparer);
}

public void SetSymbolWriter (ISymbolWriter writer)
{
symbol_writer = writer;

if (symbol_writer == null && module.HasImage && module.Image.HasDebugTables ())
symbol_writer = new PortablePdbWriter (this, module);
}

TextMap CreateTextMap ()
{
var map = new TextMap ();
Expand Down Expand Up @@ -1050,10 +1047,6 @@ void BuildModule ()

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 ()
Expand Down
4 changes: 4 additions & 0 deletions Mono.Cecil/ModuleDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,10 @@ public sealed class ModuleDefinition : ModuleReference, ICustomAttributeProvider

internal Collection<CustomDebugInformation> custom_infos;

#if !READ_ONLY
internal MetadataBuilder metadata_builder;
#endif

public bool IsMain {
get { return kind != ModuleKind.NetModule; }
}
Expand Down
122 changes: 119 additions & 3 deletions Test/Mono.Cecil.Tests/PortablePdbTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using NUnit.Framework;

using Mono.Cecil.Cil;
using Mono.Cecil.PE;

namespace Mono.Cecil.Tests {

Expand Down Expand Up @@ -347,7 +348,6 @@ public void StateMachineCustomDebugInformation ()
});
}

#if !READ_ONLY
[Test]
public void EmbeddedCompressedPortablePdb ()
{
Expand All @@ -373,7 +373,7 @@ void TestPortablePdbModule (Action<ModuleDefinition> test)
{
TestModule ("PdbTarget.exe", test, symbolReaderProvider: typeof (PortablePdbReaderProvider), symbolWriterProvider: typeof (PortablePdbWriterProvider));
TestModule ("EmbeddedPdbTarget.exe", test, verify: !Platform.OnMono);
TestModule("EmbeddedCompressedPdbTarget.exe", test, symbolReaderProvider: typeof(EmbeddedPortablePdbReaderProvider), symbolWriterProvider: typeof(EmbeddedPortablePdbWriterProvider));
TestModule ("EmbeddedCompressedPdbTarget.exe", test, symbolReaderProvider: typeof(EmbeddedPortablePdbReaderProvider), symbolWriterProvider: typeof(EmbeddedPortablePdbWriterProvider));
}

[Test]
Expand Down Expand Up @@ -553,7 +553,123 @@ public void PortablePdbLineInfo ()
IL_0001: ret", main);
}, symbolReaderProvider: typeof (PortablePdbReaderProvider), symbolWriterProvider: typeof (PortablePdbWriterProvider));
}
#endif

public sealed class SymbolWriterProvider : ISymbolWriterProvider {

readonly DefaultSymbolWriterProvider writer_provider = new DefaultSymbolWriterProvider ();

public ISymbolWriter GetSymbolWriter (ModuleDefinition module, string fileName)
{
return new SymbolWriter (writer_provider.GetSymbolWriter (module, fileName));
}

public ISymbolWriter GetSymbolWriter (ModuleDefinition module, Stream symbolStream)
{
return new SymbolWriter (writer_provider.GetSymbolWriter (module, symbolStream));
}
}

public sealed class SymbolWriter : ISymbolWriter {

readonly ISymbolWriter symbol_writer;

public SymbolWriter (ISymbolWriter symbolWriter)
{
this.symbol_writer = symbolWriter;
}

public ImageDebugHeader GetDebugHeader ()
{
var header = symbol_writer.GetDebugHeader ();
if (!header.HasEntries)
return header;

for (int i = 0; i < header.Entries.Length; i++) {
header.Entries [i] = ProcessEntry (header.Entries [i]);
}

return header;
}

private static ImageDebugHeaderEntry ProcessEntry (ImageDebugHeaderEntry entry)
{
if (entry.Directory.Type != ImageDebugType.CodeView)
return entry;

var reader = new ByteBuffer (entry.Data);
var writer = new ByteBuffer ();

var sig = reader.ReadUInt32 ();
if (sig != 0x53445352)
return entry;

writer.WriteUInt32 (sig); // RSDS
writer.WriteBytes (reader.ReadBytes (16)); // MVID
writer.WriteUInt32 (reader.ReadUInt32 ()); // Age

var length = Array.IndexOf (entry.Data, (byte) 0, reader.position) - reader.position;

var fullPath = Encoding.UTF8.GetString (reader.ReadBytes (length));

writer.WriteBytes (Encoding.UTF8.GetBytes (Path.GetFileName (fullPath)));
writer.WriteByte (0);

var newData = new byte [writer.length];
Buffer.BlockCopy (writer.buffer, 0, newData, 0, writer.length);

var directory = entry.Directory;
directory.SizeOfData = newData.Length;

return new ImageDebugHeaderEntry (directory, newData);
}

public ISymbolReaderProvider GetReaderProvider ()
{
return symbol_writer.GetReaderProvider ();
}

public void Write (MethodDebugInformation info)
{
symbol_writer.Write (info);
}

public void Dispose ()
{
symbol_writer.Dispose ();
}
}

static string GetDebugHeaderPdbPath (ModuleDefinition module)
{
var header = module.GetDebugHeader ();
var cv = Mixin.GetCodeViewEntry (header);
Assert.IsNotNull (cv);
var length = Array.IndexOf (cv.Data, (byte)0, 24) - 24;
var bytes = new byte [length];
Buffer.BlockCopy (cv.Data, 24, bytes, 0, length);
return Encoding.UTF8.GetString (bytes);
}

[Test]
public void UseCustomSymbolWriterToChangeDebugHeaderPdbPath ()
{
const string resource = "mylib.dll";

string debug_header_pdb_path;
string dest = Path.Combine (Path.GetTempPath (), resource);

using (var module = GetResourceModule (resource, new ReaderParameters { SymbolReaderProvider = new PortablePdbReaderProvider () })) {
debug_header_pdb_path = GetDebugHeaderPdbPath (module);
Assert.IsTrue (Path.IsPathRooted (debug_header_pdb_path));
module.Write (dest, new WriterParameters { SymbolWriterProvider = new SymbolWriterProvider () });
}

using (var module = ModuleDefinition.ReadModule (dest, new ReaderParameters { SymbolReaderProvider = new PortablePdbReaderProvider () })) {
var pdb_path = GetDebugHeaderPdbPath (module);
Assert.IsFalse (Path.IsPathRooted (pdb_path));
Assert.AreEqual (Path.GetFileName (debug_header_pdb_path), pdb_path);
}
}
}
}
#endif
Loading