Skip to content
Draft
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
49 changes: 49 additions & 0 deletions src/AsmResolver.DotNet/DefaultSymbolReaderFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System.IO;
using System.IO.Compression;
using System.Linq;
using AsmResolver.DotNet.PortablePdbs;
using AsmResolver.DotNet.PortablePdbs.Serialized;
using AsmResolver.DotNet.Serialized;
using AsmResolver.PE.Debug;

namespace AsmResolver.DotNet;

public class DefaultSymbolReaderFactory : ISymbolReaderFactory
{
public static DefaultSymbolReaderFactory Instance { get; } = new();

public static SerializedPortablePdb? GetPdb(SerializedModuleDefinition module)
{
if (module.DotNetDirectory.Metadata is { } metadata && PortablePdb.TryFromMetadata(metadata, module, out var pdb))
{
return pdb;
}

// System.Reflection.Metadata tries reading from a file first, so we will as well
if (module.FilePath is { } path && PortablePdb.TryFromFile(Path.ChangeExtension(path, ".pdb"), module, out pdb))
{
return pdb;
}

var pdbSection = module.DebugData.Select(dd => dd.Contents).OfType<PortablePdbDataSegment>().FirstOrDefault();
if (pdbSection is not null)
{
var memoryStream = new MemoryStream(pdbSection.CompressedContents.ToArray());
var decompressStream = new DeflateStream(memoryStream, CompressionMode.Decompress);
var pdbData = new byte[pdbSection.UncompressedSize];
var resultStream = new MemoryStream(pdbData);
decompressStream.CopyTo(resultStream);
if (PortablePdb.TryFromBytes(pdbData, module, out pdb))
{
return pdb;
}
}

return null;
}

public ISymbolReader CreateSymbolReader(SerializedModuleDefinition module)
{
return GetPdb(module) is { } pdb ? new PortablePdbSymbolReader(pdb) : NullSymbolReader.Instance;
}
}
15 changes: 15 additions & 0 deletions src/AsmResolver.DotNet/ISymbolReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System.Collections.Generic;
using AsmResolver.DotNet.PortablePdbs;
using AsmResolver.DotNet.Serialized;

namespace AsmResolver.DotNet;

public interface ISymbolReader
{
IEnumerable<Document> GetDocuments();
MethodDebugInformation? GetMethodDebugInformation(SerializedMethodDefinition method);
IEnumerable<LocalScope> GetLocalScopes(SerializedMethodDefinition method);
MethodDefinition? GetKickoffMethod(SerializedMethodDefinition method);
MethodDefinition? GetMoveNextMethod(SerializedMethodDefinition method);
IEnumerable<CustomDebugInformation> GetCustomDebugInformations(IHasCustomDebugInformation member);
}
8 changes: 8 additions & 0 deletions src/AsmResolver.DotNet/ISymbolReaderFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using AsmResolver.DotNet.Serialized;

namespace AsmResolver.DotNet;

public interface ISymbolReaderFactory
{
ISymbolReader CreateSymbolReader(SerializedModuleDefinition module);
}
33 changes: 32 additions & 1 deletion src/AsmResolver.DotNet/MethodDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using AsmResolver.DotNet.Code.Cil;
using AsmResolver.DotNet.Code.Native;
using AsmResolver.DotNet.Collections;
using AsmResolver.DotNet.PortablePdbs;
using AsmResolver.DotNet.Signatures;
using AsmResolver.PE.DotNet.Cil;
using AsmResolver.PE.DotNet.Metadata.Tables;
Expand All @@ -25,7 +26,8 @@ public partial class MethodDefinition :
IHasGenericParameters,
IMemberForwarded,
IHasSecurityDeclaration,
IManagedEntryPoint
IManagedEntryPoint,
IHasCustomDebugInformation
{
private ParameterCollection? _parameters;

Expand Down Expand Up @@ -795,6 +797,25 @@ public partial UnmanagedExportInfo? ExportInfo
set;
}

[LazyProperty]
public partial MethodDebugInformation? MethodDebugInformation
{
get;
set;
}

[LazyProperty]
public partial IList<LocalScope> LocalScopes { get; }

[LazyProperty(OwnerProperty = nameof(MoveNextMethod))]
public partial MethodDefinition? KickoffMethod { get; set; }

[LazyProperty(OwnerProperty = nameof(KickoffMethod))]
public partial MethodDefinition? MoveNextMethod { get; set; }

[LazyProperty]
public partial IList<CustomDebugInformation> CustomDebugInformations { get; }

/// <summary>
/// Creates a new private static constructor for a type that is executed when its declaring type is loaded by the CLR.
/// </summary>
Expand Down Expand Up @@ -1051,6 +1072,16 @@ protected virtual IList<GenericParameter> GetGenericParameters() =>
/// </remarks>
protected virtual UnmanagedExportInfo? GetExportInfo() => null;

protected virtual MethodDebugInformation? GetMethodDebugInformation() => null;

protected virtual IList<LocalScope> GetLocalScopes() => new MemberCollection<MethodDefinition, LocalScope>(this);

protected virtual MethodDefinition? GetKickoffMethod() => null;

protected virtual MethodDefinition? GetMoveNextMethod() => null;

protected virtual IList<CustomDebugInformation> GetCustomDebugInformations() => new MemberCollection<IHasCustomDebugInformation, CustomDebugInformation>(this);

/// <summary>
/// Asserts whether the method's metadata is consistent with its signature.
/// </summary>
Expand Down
15 changes: 14 additions & 1 deletion src/AsmResolver.DotNet/ModuleDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
using System.Threading;
using AsmResolver.Collections;
using AsmResolver.DotNet.Builder;
using AsmResolver.DotNet.Collections;
using AsmResolver.DotNet.PortablePdbs;
using AsmResolver.DotNet.Serialized;
using AsmResolver.DotNet.Signatures;
using AsmResolver.IO;
Expand All @@ -30,7 +32,8 @@ public partial class ModuleDefinition :
IResolutionScope,
IHasCustomAttribute,
IOwnedCollectionElement<AssemblyDefinition>,
ITypeOwner
ITypeOwner,
IHasCustomDebugInformation
{
private IList<TypeDefinition>? _topLevelTypes;
private IList<AssemblyReference>? _assemblyReferences;
Expand Down Expand Up @@ -810,6 +813,12 @@ public partial IManagedEntryPoint? ManagedEntryPoint
set;
}

[LazyProperty]
public partial IList<Document> Documents { get; }

[LazyProperty]
public partial IList<CustomDebugInformation> CustomDebugInformations { get; }

/// <summary>
/// Gets the default importer instance for this module.
/// </summary>
Expand Down Expand Up @@ -1250,6 +1259,10 @@ protected virtual IList<CustomAttribute> GetCustomAttributes() =>
/// </remarks>
protected virtual ReferenceImporter GetDefaultImporter() => new(this);

protected virtual IList<Document> GetDocuments() => new MemberCollection<ModuleDefinition, Document>(this);

protected virtual IList<CustomDebugInformation> GetCustomDebugInformations() => new MemberCollection<IHasCustomDebugInformation, CustomDebugInformation>(this);

/// <summary>
/// Detects the runtime that this module targets.
/// </summary>
Expand Down
22 changes: 22 additions & 0 deletions src/AsmResolver.DotNet/NullSymbolReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System.Collections.Generic;
using AsmResolver.DotNet.PortablePdbs;
using AsmResolver.DotNet.Serialized;

namespace AsmResolver.DotNet;

public class NullSymbolReader : ISymbolReader
{
public static NullSymbolReader Instance { get; } = new();

public IEnumerable<Document> GetDocuments() => [];

public MethodDebugInformation? GetMethodDebugInformation(SerializedMethodDefinition method) => null;

public IEnumerable<LocalScope> GetLocalScopes(SerializedMethodDefinition method) => [];

public MethodDefinition? GetKickoffMethod(SerializedMethodDefinition method) => null;

public MethodDefinition? GetMoveNextMethod(SerializedMethodDefinition method) => null;

public IEnumerable<CustomDebugInformation> GetCustomDebugInformations(IHasCustomDebugInformation member) => [];
}
36 changes: 36 additions & 0 deletions src/AsmResolver.DotNet/PortablePdbs/CustomDebugInformation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using AsmResolver.Collections;
using AsmResolver.DotNet.PortablePdbs.CustomRecords;
using AsmResolver.PE.DotNet.Metadata.Tables;

namespace AsmResolver.DotNet.PortablePdbs;

public partial class CustomDebugInformation : IMetadataMember, IOwnedCollectionElement<IHasCustomDebugInformation>
{
public CustomDebugInformation(MetadataToken token)
{
MetadataToken = token;
}

public MetadataToken MetadataToken
{
get;
}

[LazyProperty]
public partial IHasCustomDebugInformation? Owner
{
get;
set;
}

[LazyProperty]
public partial CustomDebugRecord? Value
{
get;
set;
}

protected virtual IHasCustomDebugInformation? GetOwner() => null;

protected virtual CustomDebugRecord? GetValue() => null;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using AsmResolver.DotNet.PortablePdbs.Serialized;
using AsmResolver.DotNet.Signatures;
using AsmResolver.IO;
using AsmResolver.PE.DotNet.Metadata.Tables;

namespace AsmResolver.DotNet.PortablePdbs.CustomRecords;

public class AsyncMethodSteppingInformationRecord : CustomDebugRecord
{
public static Guid KnownKind { get; } = new("54FD2AC5-E925-401A-9C2A-F94F171072F8");

public override Guid Kind => KnownKind;

public override bool HasBlob => true;

public uint CatchHandlerOffset { get; set; }

public OffsetPair[]? Pairs { get; set; }

public static unsafe AsyncMethodSteppingInformationRecord FromReader(PdbReaderContext context, ref BinaryStreamReader reader)
{
var catchOffset = reader.ReadUInt32();
var pairList = new List<OffsetPair>();
while (reader.CanRead(1))
{
pairList.Add(new OffsetPair
{
YieldOffset = reader.ReadUInt32(),
ResumeOffset = reader.ReadUInt32(),
ResumeMethod = context.OwningModule.LookupMember<MethodDefinition>(new MetadataToken(TableIndex.Method, reader.ReadCompressedUInt32())),
});
}
return new AsyncMethodSteppingInformationRecord
{
CatchHandlerOffset = catchOffset,
Pairs = pairList.ToArray(),
};
}

protected override void WriteContents(in BlobSerializationContext context)
{
throw new NotImplementedException();
}

public struct OffsetPair
{
public uint YieldOffset { get; set; }
public uint ResumeOffset { get; set; }
public MethodDefinition ResumeMethod { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
using AsmResolver.DotNet.PortablePdbs.Serialized;
using AsmResolver.DotNet.Signatures;
using AsmResolver.IO;
using AsmResolver.Shims;

namespace AsmResolver.DotNet.PortablePdbs.CustomRecords;

public class CompilationMetadataReferencesRecord : CustomDebugRecord
{
public static Guid KnownKind { get; } = new("7E4D4708-096E-4C5C-AEDA-CB10BA6A740D");

public override Guid Kind => KnownKind;

public override bool HasBlob => true;

public MetadataReferenceInfo[]? References { get; set; }

public static CompilationMetadataReferencesRecord FromReader(PdbReaderContext context, ref BinaryStreamReader reader)
{
var referenceList = new List<MetadataReferenceInfo>();
while (reader.CanRead(1))
{
var fileName = reader.ReadUtf8String();
var aliasesString = reader.ReadUtf8String();
Utf8String[] aliases;
if (aliasesString.GetBytesUnsafe().Contains((byte)','))
{
aliases = Array.ConvertAll(aliasesString.Value.Split(','), alias => (Utf8String)alias);
}
else if (aliasesString.Length != 0)
{
aliases = [aliasesString];
}
else
{
aliases = ArrayShim.Empty<Utf8String>();
}
var flags = (MetadataReferenceFlags)reader.ReadByte();
var timeStamp = new DateTime(1970, 1, 1) + TimeSpan.FromSeconds(reader.ReadUInt32());
var fileSize = reader.ReadUInt32();
var mvid = new Guid(reader.ReadBytes(16));

referenceList.Add(new MetadataReferenceInfo
{
FileName = fileName,
Aliases = aliases,
Flags = flags,
TimeStamp = timeStamp,
FileSize = fileSize,
Mvid = mvid,
});
}

return new CompilationMetadataReferencesRecord
{
References = referenceList.ToArray(),
};
}

protected override void WriteContents(in BlobSerializationContext context)
{
throw new NotImplementedException();
}

public struct MetadataReferenceInfo
{
public Utf8String? FileName { get; set; }
public Utf8String[]? Aliases { get; set; }
public MetadataReferenceFlags Flags { get; set; }
public DateTime TimeStamp { get; set; }
public uint FileSize { get; set; }
public Guid Mvid { get; set; }
}

public enum MetadataReferenceFlags
{
None = 0,
AssemblyReference = 1,
EmbeddedInteropTypes = 2,
}
}
Loading
Loading