Skip to content

Commit

Permalink
Add support for the portable pdb format
Browse files Browse the repository at this point in the history
  • Loading branch information
jbevain committed Jul 13, 2016
1 parent 7efc4a6 commit 7cde491
Show file tree
Hide file tree
Showing 56 changed files with 3,353 additions and 843 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ obj
**/test-results/*
*Resharper*
Mono.Cecil.sln.ide*
TestResults
134 changes: 102 additions & 32 deletions Mono.Cecil.Cil/CodeReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,99 @@ void ReadMethodBody ()

var symbol_reader = reader.module.symbol_reader;

if (symbol_reader != null) {
var instructions = body.Instructions;
symbol_reader.Read (body, offset => GetInstruction (instructions, offset));
if (symbol_reader != null && method.debug_info == null)
method.debug_info = symbol_reader.Read (method);

if (method.debug_info != null)
ReadDebugInfo ();
}

void ReadDebugInfo ()
{
ReadSequencePoints ();

if (method.debug_info.scope != null)
ReadScope (method.debug_info.scope);

if (method.custom_infos != null)
ReadCustomDebugInformations (method);
}

void ReadCustomDebugInformations (MethodDefinition method)
{
var custom_infos = method.custom_infos;

for (int i = 0; i < custom_infos.Count; i++) {
var state_machine_scope = custom_infos [i] as StateMachineScopeDebugInformation;
if (state_machine_scope != null)
ReadStateMachineScope (state_machine_scope);

var async_method = custom_infos [i] as AsyncMethodBodyDebugInformation;
if (async_method != null)
ReadAsyncMethodBody (async_method);
}
}

void ReadAsyncMethodBody (AsyncMethodBodyDebugInformation async_method)
{
if (async_method.catch_handler.Offset > -1)
async_method.catch_handler = new InstructionOffset (GetInstruction (async_method.catch_handler.Offset));

if (!async_method.yields.IsNullOrEmpty ())
for (int i = 0; i < async_method.yields.Count; i++)
async_method.yields [i] = new InstructionOffset (GetInstruction (async_method.yields [i].Offset));

if (!async_method.resumes.IsNullOrEmpty ())
for (int i = 0; i < async_method.resumes.Count; i++)
async_method.resumes [i] = new InstructionOffset (GetInstruction (async_method.resumes [i].Offset));
}

void ReadStateMachineScope (StateMachineScopeDebugInformation state_machine_scope)
{
state_machine_scope.start = new InstructionOffset (GetInstruction (state_machine_scope.start.Offset));

var end_instruction = GetInstruction (state_machine_scope.end.Offset);
state_machine_scope.end = end_instruction == null
? new InstructionOffset ()
: new InstructionOffset (end_instruction);
}

void ReadSequencePoints ()
{
var symbol = method.debug_info;

for (int i = 0; i < symbol.sequence_points.Count; i++) {
var sequence_point = symbol.sequence_points [i];
var instruction = GetInstruction (sequence_point.Offset);
if (instruction != null)
sequence_point.offset = new InstructionOffset (instruction);
}
}

void ReadScopes (Collection<ScopeDebugInformation> scopes)
{
for (int i = 0; i < scopes.Count; i++)
ReadScope (scopes [i]);
}

void ReadScope (ScopeDebugInformation scope)
{
scope.Start = new InstructionOffset (GetInstruction (scope.Start.Offset));

var end_instruction = GetInstruction (scope.End.Offset);
scope.End = end_instruction == null
? new InstructionOffset ()
: new InstructionOffset (end_instruction);

if (!scope.variables.IsNullOrEmpty ()) {
for (int i = 0; i < scope.variables.Count; i++) {
var variable = scope.variables [i];
variable.index = new VariableIndex (GetVariable (variable.Index));
}
}

if (!scope.scopes.IsNullOrEmpty ())
ReadScopes (scope.scopes);
}

void ReadFatMethod ()
Expand Down Expand Up @@ -361,10 +450,9 @@ public MetadataToken ReadToken ()

#if !READ_ONLY

public ByteBuffer PatchRawMethodBody (MethodDefinition method, CodeWriter writer, out MethodSymbols symbols)
public ByteBuffer PatchRawMethodBody (MethodDefinition method, CodeWriter writer, out int code_size, out MetadataToken local_var_token)
{
var buffer = new ByteBuffer ();
symbols = new MethodSymbols (method.Name);

this.method = method;
reader.context = method;
Expand All @@ -373,66 +461,48 @@ public ByteBuffer PatchRawMethodBody (MethodDefinition method, CodeWriter writer

var flags = ReadByte ();

MetadataToken local_var_token;

switch (flags & 0x3) {
case 0x2: // tiny
buffer.WriteByte (flags);
local_var_token = MetadataToken.Zero;
symbols.code_size = flags >> 2;
PatchRawCode (buffer, symbols.code_size, writer);
code_size = flags >> 2;
PatchRawCode (buffer, code_size, writer);
break;
case 0x3: // fat
base.position--;

PatchRawFatMethod (buffer, symbols, writer, out local_var_token);
PatchRawFatMethod (buffer, writer, out code_size, out local_var_token);
break;
default:
throw new NotSupportedException ();
}

var symbol_reader = reader.module.symbol_reader;
if (symbol_reader != null && writer.metadata.write_symbols) {
symbols.method_token = GetOriginalToken (writer.metadata, method);
symbols.local_var_token = local_var_token;
symbol_reader.Read (symbols);
}

return buffer;
}

void PatchRawFatMethod (ByteBuffer buffer, MethodSymbols symbols, CodeWriter writer, out MetadataToken local_var_token)
void PatchRawFatMethod (ByteBuffer buffer, CodeWriter writer, out int code_size, out MetadataToken local_var_token)
{
var flags = ReadUInt16 ();
buffer.WriteUInt16 (flags);
buffer.WriteUInt16 (ReadUInt16 ());
symbols.code_size = ReadInt32 ();
buffer.WriteInt32 (symbols.code_size);
code_size = ReadInt32 ();
buffer.WriteInt32 (code_size);
local_var_token = ReadToken ();

if (local_var_token.RID > 0) {
var variables = symbols.variables = ReadVariables (local_var_token);
var variables = ReadVariables (local_var_token);
buffer.WriteUInt32 (variables != null
? writer.GetStandAloneSignature (symbols.variables).ToUInt32 ()
? writer.GetStandAloneSignature (variables).ToUInt32 ()
: 0);
} else
buffer.WriteUInt32 (0);

PatchRawCode (buffer, symbols.code_size, writer);
PatchRawCode (buffer, code_size, writer);

if ((flags & 0x8) != 0)
PatchRawSection (buffer, writer.metadata);
}

static MetadataToken GetOriginalToken (MetadataBuilder metadata, MethodDefinition method)
{
MetadataToken original;
if (metadata.TryGetOriginalMethodToken (method.token, out original))
return original;

return MetadataToken.Zero;
}

void PatchRawCode (ByteBuffer buffer, int code_size, CodeWriter writer)
{
var metadata = writer.metadata;
Expand Down
33 changes: 14 additions & 19 deletions Mono.Cecil.Cil/CodeWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,29 +77,21 @@ void WriteUnresolvedMethodBody (MethodDefinition method)
{
var code_reader = metadata.module.Read (method, (_, reader) => reader.code);

MethodSymbols symbols;
var buffer = code_reader.PatchRawMethodBody (method, this, out symbols);
int code_size;
MetadataToken local_var_token;
var buffer = code_reader.PatchRawMethodBody (method, this, out code_size, out local_var_token);

WriteBytes (buffer);

if (symbols.instructions.IsNullOrEmpty ())
if (method.debug_info == null)
return;

symbols.method_token = method.token;
symbols.local_var_token = GetLocalVarToken (buffer, symbols);

var symbol_writer = metadata.symbol_writer;
if (symbol_writer != null)
symbol_writer.Write (symbols);
}

static MetadataToken GetLocalVarToken (ByteBuffer buffer, MethodSymbols symbols)
{
if (symbols.variables.IsNullOrEmpty ())
return MetadataToken.Zero;

buffer.position = 8;
return new MetadataToken (buffer.ReadUInt32 ());
if (symbol_writer != null) {
method.debug_info.code_size = code_size;
method.debug_info.local_var_token = local_var_token;
symbol_writer.Write (method.debug_info);
}
}

void WriteResolvedMethodBody (MethodDefinition method)
Expand All @@ -117,8 +109,11 @@ void WriteResolvedMethodBody (MethodDefinition method)
WriteExceptionHandlers ();

var symbol_writer = metadata.symbol_writer;
if (symbol_writer != null)
symbol_writer.Write (body);
if (symbol_writer != null && method.debug_info != null) {
method.debug_info.code_size = body.CodeSize;
method.debug_info.local_var_token = body.local_var_token;
symbol_writer.Write (method.debug_info);
}
}

void WriteFatHeader ()
Expand Down
4 changes: 3 additions & 1 deletion Mono.Cecil.Cil/Document.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public enum DocumentHashAlgorithm {
None,
MD5,
SHA1,
SHA256,
}

public enum DocumentLanguage {
Expand All @@ -44,7 +45,7 @@ public enum DocumentLanguageVendor {
Microsoft,
}

public sealed class Document {
public sealed class Document : DebugInformation {

string url;

Expand Down Expand Up @@ -89,6 +90,7 @@ public Document (string url)
{
this.url = url;
this.hash = Empty<byte>.Array;
this.token = new MetadataToken (TokenType.Document);
}
}
}
7 changes: 0 additions & 7 deletions Mono.Cecil.Cil/Instruction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ public sealed class Instruction {
internal Instruction previous;
internal Instruction next;

SequencePoint sequence_point;

public int Offset {
get { return offset; }
set { offset = value; }
Expand All @@ -49,11 +47,6 @@ public Instruction Next {
set { next = value; }
}

public SequencePoint SequencePoint {
get { return sequence_point; }
set { sequence_point = value; }
}

internal Instruction (int offset, OpCode opCode)
{
this.offset = offset;
Expand Down
13 changes: 1 addition & 12 deletions Mono.Cecil.Cil/MethodBody.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

namespace Mono.Cecil.Cil {

public sealed class MethodBody : IVariableDefinitionProvider {
public sealed class MethodBody {

readonly internal MethodDefinition method;

Expand All @@ -28,7 +28,6 @@ public sealed class MethodBody : IVariableDefinitionProvider {
internal Collection<Instruction> instructions;
internal Collection<ExceptionHandler> exceptions;
internal Collection<VariableDefinition> variables;
Scope scope;

public MethodDefinition Method {
get { return method; }
Expand Down Expand Up @@ -73,11 +72,6 @@ public Collection<VariableDefinition> Variables {
get { return variables ?? (variables = new VariableDefinitionCollection ()); }
}

public Scope Scope {
get { return scope; }
set { scope = value; }
}

public ParameterDefinition ThisParameter {
get {
if (method == null || method.DeclaringType == null)
Expand Down Expand Up @@ -114,11 +108,6 @@ public ILProcessor GetILProcessor ()
}
}

public interface IVariableDefinitionProvider {
bool HasVariables { get; }
Collection<VariableDefinition> Variables { get; }
}

class VariableDefinitionCollection : Collection<VariableDefinition> {

internal VariableDefinitionCollection ()
Expand Down
Loading

0 comments on commit 7cde491

Please sign in to comment.