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

Add support for deterministic debug directory #349

Merged
merged 1 commit into from
Mar 13, 2017
Merged
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
5 changes: 1 addition & 4 deletions Mono.Cecil.Cil/PortablePdb.cs
Original file line number Diff line number Diff line change
@@ -150,10 +150,7 @@ public ISymbolReader GetSymbolReader (ModuleDefinition module, string fileName)
Mixin.CheckModule (module);
Mixin.CheckFileName (fileName);

var header = module.Image.GetDebugHeader ();
if (header == null)
throw new InvalidOperationException ();

var header = module.GetDebugHeader ();
var entry = header.GetEmbeddedPortablePdbEntry ();
if (entry == null)
throw new InvalidOperationException ();
17 changes: 17 additions & 0 deletions Mono.Cecil.Cil/Symbols.cs
Original file line number Diff line number Diff line change
@@ -906,6 +906,23 @@ public static ImageDebugHeaderEntry GetCodeViewEntry (this ImageDebugHeader head
return GetEntry (header, ImageDebugType.CodeView);
}

public static ImageDebugHeaderEntry GetDeterministicEntry (this ImageDebugHeader header)
{
return GetEntry (header, ImageDebugType.Deterministic);
}

public static ImageDebugHeader AddDeterministicEntry (this ImageDebugHeader header)
{
var entry = new ImageDebugHeaderEntry (new ImageDebugDirectory { Type = ImageDebugType.Deterministic }, Empty<byte>.Array);
if (header == null)
return new ImageDebugHeader (entry);

var entries = new ImageDebugHeaderEntry [header.Entries.Length + 1];
Array.Copy (header.Entries, entries, header.Entries.Length);
entries [entries.Length - 1] = entry;
return new ImageDebugHeader (entries);
}

public static ImageDebugHeaderEntry GetEmbeddedPortablePdbEntry (this ImageDebugHeader header)
{
return GetEntry (header, ImageDebugType.EmbeddedPortablePdb);
40 changes: 2 additions & 38 deletions Mono.Cecil.PE/Image.cs
Original file line number Diff line number Diff line change
@@ -29,6 +29,8 @@ sealed class Image : IDisposable {
public TargetArchitecture Architecture;
public ModuleCharacteristics Characteristics;

public ImageDebugHeader DebugHeader;

public Section [] Sections;

public Section MetadataSection;
@@ -145,44 +147,6 @@ public TRet GetReaderAt<TItem, TRet> (RVA rva, TItem item, Func<TItem, BinaryStr
}
}

public ImageDebugHeader GetDebugHeader ()
{
var reader = GetReaderAt (Debug.VirtualAddress);
if (reader == null) {
return new ImageDebugHeader (Empty<ImageDebugHeaderEntry>.Array);
}

var count = (int) Debug.Size / ImageDebugDirectory.Size;
var collection = new Collection<ImageDebugHeaderEntry> (count);

for (int i = 0; i < count; i++) {
var directory = new ImageDebugDirectory {
Characteristics = reader.ReadInt32 (),
TimeDateStamp = reader.ReadInt32 (),
MajorVersion = reader.ReadInt16 (),
MinorVersion = reader.ReadInt16 (),
Type = (ImageDebugType) reader.ReadInt32 (),
SizeOfData = reader.ReadInt32 (),
AddressOfRawData = reader.ReadInt32 (),
PointerToRawData = reader.ReadInt32 (),
};

var position = reader.Position;
try {
var data_reader = GetReaderAt ((uint) directory.AddressOfRawData);
var data = data_reader != null
? reader.ReadBytes (directory.SizeOfData)
: Empty<byte>.Array;

collection.Add (new ImageDebugHeaderEntry (directory, data));
} finally {
reader.Position = position;
}
}

return new ImageDebugHeader (collection.ToArray ());
}

public bool HasDebugTables ()
{
return HasTable (Table.Document)
44 changes: 44 additions & 0 deletions Mono.Cecil.PE/ImageReader.cs
Original file line number Diff line number Diff line change
@@ -11,7 +11,9 @@
using System;
using System.IO;

using Mono.Cecil.Cil;
using Mono.Cecil.Metadata;
using Mono.Collections.Generic;

using RVA = System.UInt32;

@@ -84,6 +86,7 @@ void ReadImage ()
ReadSections (sections);
ReadCLIHeader ();
ReadMetadata ();
ReadDebugHeader ();

image.Kind = GetModuleKind (characteristics, subsystem);
image.Characteristics = (ModuleCharacteristics) dll_characteristics;
@@ -314,6 +317,47 @@ void ReadMetadata ()
ReadPdbHeap ();
}

void ReadDebugHeader ()
{
if (image.Debug.IsZero) {
image.DebugHeader = new ImageDebugHeader (Empty<ImageDebugHeaderEntry>.Array);
return;
}

MoveTo (image.Debug);

var entries = new ImageDebugHeaderEntry [(int) image.Debug.Size / ImageDebugDirectory.Size];

for (int i = 0; i < entries.Length; i++) {
var directory = new ImageDebugDirectory {
Characteristics = ReadInt32 (),
TimeDateStamp = ReadInt32 (),
MajorVersion = ReadInt16 (),
MinorVersion = ReadInt16 (),
Type = (ImageDebugType) ReadInt32 (),
SizeOfData = ReadInt32 (),
AddressOfRawData = ReadInt32 (),
PointerToRawData = ReadInt32 (),
};

if (directory.AddressOfRawData == 0) {
entries [i] = new ImageDebugHeaderEntry (directory, Empty<byte>.Array);
continue;
}

var position = Position;
try {
MoveTo ((uint) directory.PointerToRawData);
var data = ReadBytes (directory.SizeOfData);
entries [i] = new ImageDebugHeaderEntry (directory, data);
} finally {
Position = position;
}
}

image.DebugHeader = new ImageDebugHeader (entries);
}

void ReadMetadataStream (Section section)
{
// Offset 4
13 changes: 10 additions & 3 deletions Mono.Cecil.PE/ImageWriter.cs
Original file line number Diff line number Diff line change
@@ -72,10 +72,17 @@ sealed class ImageWriter : BinaryStreamWriter {
void GetDebugHeader ()
{
var symbol_writer = metadata.symbol_writer;
if (symbol_writer == null)
return;
if (symbol_writer != null)
debug_header = symbol_writer.GetDebugHeader ();

if (module.HasDebugHeader) {
var header = module.GetDebugHeader ();
var deterministic = header.GetDeterministicEntry ();
if (deterministic == null)
return;

debug_header = symbol_writer.GetDebugHeader ();
debug_header = debug_header.AddDeterministicEntry ();
}
}

void GetWin32Resources ()
4 changes: 2 additions & 2 deletions Mono.Cecil/ModuleDefinition.cs
Original file line number Diff line number Diff line change
@@ -986,15 +986,15 @@ internal TRet Read<TItem, TRet> (ref TRet variable, TItem item, Func<TItem, Meta
}

public bool HasDebugHeader {
get { return Image != null && !Image.Debug.IsZero; }
get { return Image != null && Image.DebugHeader != null; }
}

public ImageDebugHeader GetDebugHeader ()
{
if (!HasDebugHeader)
throw new InvalidOperationException ();

return Image.GetDebugHeader ();
return Image.DebugHeader;
}

void ProcessDebugHeader ()
44 changes: 44 additions & 0 deletions Test/Mono.Cecil.Tests/ImageReadTests.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System;
using System.IO;
using System.Linq;

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

@@ -179,5 +181,47 @@ public void WindowsRuntimeComponentAssembly ()
Assert.IsTrue (module.Assembly.Name.IsWindowsRuntime);
}, verify: false, assemblyResolver: resolver);
}

[Test]
public void DeterministicAssembly ()
{
TestModule ("Deterministic.dll", module => {
Assert.IsTrue (module.HasDebugHeader);

var header = module.GetDebugHeader ();

Assert.AreEqual (1, header.Entries.Length);
Assert.IsTrue (header.Entries.Any (e => e.Directory.Type == ImageDebugType.Deterministic));
});
}

[Test]
public void ExternalPdbDeterministicAssembly ()
{
TestModule ("ExternalPdbDeterministic.dll", module => {
Assert.IsTrue (module.HasDebugHeader);

var header = module.GetDebugHeader ();

Assert.AreEqual (2, header.Entries.Length);
Assert.IsTrue (header.Entries.Any (e => e.Directory.Type == ImageDebugType.CodeView));
Assert.IsTrue (header.Entries.Any (e => e.Directory.Type == ImageDebugType.Deterministic));
}, symbolReaderProvider: typeof (PortablePdbReaderProvider), symbolWriterProvider: typeof (PortablePdbWriterProvider));
}

[Test]
public void EmbeddedPdbDeterministicAssembly ()
{
TestModule ("EmbeddedPdbDeterministic.dll", module => {
Assert.IsTrue (module.HasDebugHeader);

var header = module.GetDebugHeader ();

Assert.AreEqual (3, header.Entries.Length);
Assert.IsTrue (header.Entries.Any (e => e.Directory.Type == ImageDebugType.CodeView));
Assert.IsTrue (header.Entries.Any (e => e.Directory.Type == ImageDebugType.Deterministic));
Assert.IsTrue (header.Entries.Any (e => e.Directory.Type == ImageDebugType.EmbeddedPortablePdb));
}, symbolReaderProvider: typeof (EmbeddedPortablePdbReaderProvider), symbolWriterProvider: typeof (EmbeddedPortablePdbWriterProvider));
}
}
}
Binary file added Test/Resources/assemblies/Deterministic.dll
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.