Skip to content

Commit 5ac5820

Browse files
committed
bad prototype
1 parent afd343f commit 5ac5820

20 files changed

+944
-26
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System.IO;
2+
using System.IO.Compression;
3+
using System.Linq;
4+
using AsmResolver.DotNet.PortablePdbs;
5+
using AsmResolver.PE.Debug;
6+
7+
namespace AsmResolver.DotNet;
8+
9+
public class DefaultPdbMetadataResolver : IPdbMetadataResolver
10+
{
11+
public static DefaultPdbMetadataResolver Instance { get; } = new();
12+
13+
public PortablePdb? ResolvePortablePdb(ModuleDefinition module)
14+
{
15+
if (module.DotNetDirectory?.Metadata is { } metadata && PortablePdb.TryFromMetadata(metadata, module, out var pdb))
16+
{
17+
return pdb;
18+
}
19+
20+
// System.Reflection.Metadata tries reading from a file first, so we will as well
21+
if (module.FilePath is { } path && PortablePdb.TryFromFile(Path.ChangeExtension(path, ".pdb"), module, out pdb))
22+
{
23+
return pdb;
24+
}
25+
26+
var pdbSection = module.DebugData.Select(dd => dd.Contents).OfType<PortablePdbDataSegment>().FirstOrDefault();
27+
if (pdbSection is not null)
28+
{
29+
var memoryStream = new MemoryStream(pdbSection.CompressedContents.ToArray());
30+
var decompressStream = new DeflateStream(memoryStream, CompressionMode.Decompress);
31+
var pdbData = new byte[pdbSection.UncompressedSize];
32+
var resultStream = new MemoryStream(pdbData);
33+
decompressStream.CopyTo(resultStream);
34+
if (PortablePdb.TryFromBytes(pdbData, module, out pdb))
35+
{
36+
return pdb;
37+
}
38+
}
39+
40+
return null;
41+
}
42+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using AsmResolver.DotNet.PortablePdbs;
2+
3+
namespace AsmResolver.DotNet
4+
{
5+
public interface IPdbMetadataResolver
6+
{
7+
PortablePdb? ResolvePortablePdb(ModuleDefinition module);
8+
}
9+
}

src/AsmResolver.DotNet/MethodDefinition.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using AsmResolver.DotNet.Code.Cil;
88
using AsmResolver.DotNet.Code.Native;
99
using AsmResolver.DotNet.Collections;
10+
using AsmResolver.DotNet.PortablePdbs;
1011
using AsmResolver.DotNet.Signatures;
1112
using AsmResolver.PE.DotNet.Cil;
1213
using AsmResolver.PE.DotNet.Metadata.Tables;
@@ -34,6 +35,7 @@ public class MethodDefinition :
3435
private readonly LazyVariable<MethodDefinition, ImplementationMap?> _implementationMap;
3536
private readonly LazyVariable<MethodDefinition, MethodSemantics?> _semantics;
3637
private readonly LazyVariable<MethodDefinition, UnmanagedExportInfo?> _exportInfo;
38+
private readonly LazyVariable<MethodDefinition, MethodDebugInformation> _methodDebugInformation;
3739
private IList<ParameterDefinition>? _parameterDefinitions;
3840
private ParameterCollection? _parameters;
3941
private IList<CustomAttribute>? _customAttributes;
@@ -60,6 +62,12 @@ protected MethodDefinition(MetadataToken token)
6062
_implementationMap = new LazyVariable<MethodDefinition, ImplementationMap?>(x => x.GetImplementationMap());
6163
_semantics = new LazyVariable<MethodDefinition, MethodSemantics?>(x => x.GetSemantics());
6264
_exportInfo = new LazyVariable<MethodDefinition, UnmanagedExportInfo?>(x => x.GetExportInfo());
65+
_methodDebugInformation = new LazyVariable<MethodDefinition, MethodDebugInformation>(x =>
66+
{
67+
MethodDebugInformation? mdi = null;
68+
_ = x.DeclaringModule?.PortablePdb?.TryLookupMember(new MetadataToken(TableIndex.MethodDebugInformation, x.MetadataToken.Rid), out mdi);
69+
return mdi ?? new MethodDebugInformation(new MetadataToken(TableIndex.MethodDebugInformation, x.MetadataToken.Rid));
70+
});
6371
}
6472

6573
/// <summary>
@@ -792,6 +800,12 @@ public UnmanagedExportInfo? ExportInfo
792800
set => _exportInfo.SetValue(value);
793801
}
794802

803+
public MethodDebugInformation MethodDebugInformation
804+
{
805+
get => _methodDebugInformation.GetValue(this);
806+
set => _methodDebugInformation.SetValue(value);
807+
}
808+
795809
/// <summary>
796810
/// Creates a new private static constructor for a type that is executed when its declaring type is loaded by the CLR.
797811
/// </summary>

src/AsmResolver.DotNet/ModuleDefinition.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Threading;
88
using AsmResolver.Collections;
99
using AsmResolver.DotNet.Builder;
10+
using AsmResolver.DotNet.PortablePdbs;
1011
using AsmResolver.DotNet.Serialized;
1112
using AsmResolver.DotNet.Signatures;
1213
using AsmResolver.IO;
@@ -53,6 +54,8 @@ public class ModuleDefinition :
5354
private IList<DebugDataEntry>? _debugData;
5455
private ReferenceImporter? _defaultImporter;
5556

57+
private readonly LazyVariable<ModuleDefinition, PortablePdb?> _portablePdb;
58+
5659
/// <summary>
5760
/// Reads a .NET module from the provided input buffer.
5861
/// </summary>
@@ -299,6 +302,7 @@ protected ModuleDefinition(MetadataToken token)
299302
_managedEntryPoint = new LazyVariable<ModuleDefinition, IManagedEntryPoint?>(x => x.GetManagedEntryPoint());
300303
_runtimeVersion = new LazyVariable<ModuleDefinition, string>(x => x.GetRuntimeVersion());
301304
_nativeResources = new LazyVariable<ModuleDefinition, ResourceDirectory?>(x => x.GetNativeResources());
305+
_portablePdb = new LazyVariable<ModuleDefinition, PortablePdb?>(x => x.GetPortablePdb());
302306
Attributes = DotNetDirectoryFlags.ILOnly;
303307
}
304308

@@ -362,6 +366,12 @@ public virtual DotNetDirectory? DotNetDirectory
362366
get;
363367
} = null;
364368

369+
public PortablePdb? PortablePdb
370+
{
371+
get => _portablePdb.GetValue(this);
372+
set => _portablePdb.SetValue(value);
373+
}
374+
365375
/// <summary>
366376
/// Gets the object describing the current active runtime context the module is loaded in.
367377
/// </summary>
@@ -1189,6 +1199,8 @@ protected virtual IList<ExportedType> GetExportedTypes() =>
11891199
protected virtual IList<CustomAttribute> GetCustomAttributes() =>
11901200
new OwnedCollection<IHasCustomAttribute, CustomAttribute>(this);
11911201

1202+
protected virtual PortablePdb? GetPortablePdb() => null;
1203+
11921204
AssemblyDescriptor? IResolutionScope.GetAssembly() => Assembly;
11931205

11941206
/// <summary>
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
using System;
2+
using System.Diagnostics;
3+
using AsmResolver.Collections;
4+
using AsmResolver.PE.DotNet.Metadata.Tables;
5+
6+
namespace AsmResolver.DotNet.PortablePdbs
7+
{
8+
[DebuggerDisplay("{Name}")]
9+
public class Document : IMetadataMember, IOwnedCollectionElement<PortablePdb>
10+
{
11+
private readonly LazyVariable<Document, Utf8String?> _name;
12+
private readonly LazyVariable<Document, Guid> _hashAlgorithm;
13+
private readonly LazyVariable<Document, byte[]?> _hash;
14+
private readonly LazyVariable<Document, Guid> _language;
15+
16+
public Document() : this(new MetadataToken(TableIndex.Document, 0)) { }
17+
18+
public Document(MetadataToken token)
19+
{
20+
MetadataToken = token;
21+
22+
_name = new LazyVariable<Document, Utf8String?>(doc => doc.GetName());
23+
_hashAlgorithm = new LazyVariable<Document, Guid>(doc => doc.GetHashAlgorithm());
24+
_hash = new LazyVariable<Document, byte[]?>(doc => doc.GetHash());
25+
_language = new LazyVariable<Document, Guid>(doc => doc.GetLanguage());
26+
}
27+
28+
public MetadataToken MetadataToken { get; }
29+
30+
public PortablePdb? Owner
31+
{
32+
get;
33+
set;
34+
}
35+
36+
public Utf8String? Name
37+
{
38+
get => _name.GetValue(this);
39+
set => _name.SetValue(value);
40+
}
41+
42+
public Guid HashAlgorithm
43+
{
44+
get => _hashAlgorithm.GetValue(this);
45+
set => _hashAlgorithm.SetValue(value);
46+
}
47+
48+
public byte[]? Hash
49+
{
50+
get => _hash.GetValue(this);
51+
set => _hash.SetValue(value);
52+
}
53+
54+
public Guid Language
55+
{
56+
get => _language.GetValue(this);
57+
set => _language.SetValue(value);
58+
}
59+
60+
protected virtual Utf8String? GetName() => null;
61+
62+
protected virtual Guid GetHashAlgorithm() => Guid.Empty;
63+
64+
protected virtual byte[]? GetHash() => null;
65+
66+
protected virtual Guid GetLanguage() => Guid.Empty;
67+
}
68+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using AsmResolver.PE.DotNet.Metadata.Tables;
2+
3+
namespace AsmResolver.DotNet.PortablePdbs
4+
{
5+
public class MethodDebugInformation : IMetadataMember
6+
{
7+
private readonly LazyVariable<MethodDebugInformation, Document?> _document;
8+
private readonly LazyVariable<MethodDebugInformation, SequencePointCollection> _sequencePoints;
9+
10+
public MethodDebugInformation(Document document) : this(new MetadataToken(TableIndex.MethodDebugInformation, 0))
11+
{
12+
Document = document;
13+
}
14+
15+
public MethodDebugInformation(MetadataToken token)
16+
{
17+
MetadataToken = token;
18+
19+
_document = new(mdi => mdi.GetDocument());
20+
_sequencePoints = new(mdi => mdi.GetSequencePoints());
21+
}
22+
23+
public MetadataToken MetadataToken { get; }
24+
25+
public Document? Document
26+
{
27+
get => _document.GetValue(this);
28+
set => _document.SetValue(value);
29+
}
30+
31+
public SequencePointCollection SequencePoints => _sequencePoints.GetValue(this);
32+
33+
protected virtual Document? GetDocument() => null;
34+
35+
protected virtual SequencePointCollection GetSequencePoints() => new(this);
36+
}
37+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
using System.Collections.Generic;
2+
using System.Diagnostics.CodeAnalysis;
3+
using AsmResolver.DotNet.PortablePdbs.Serialized;
4+
using AsmResolver.PE.DotNet.Metadata;
5+
using AsmResolver.PE.DotNet.Metadata.Tables;
6+
7+
namespace AsmResolver.DotNet.PortablePdbs
8+
{
9+
public class PortablePdb
10+
{
11+
private readonly LazyVariable<PortablePdb, IList<Document>> _documents;
12+
13+
public PortablePdb(ModuleDefinition? ownerModule)
14+
{
15+
Owner = ownerModule;
16+
17+
_documents = new LazyVariable<PortablePdb, IList<Document>>(pdb => pdb.GetDocuments());
18+
}
19+
20+
public static bool TryFromFile(string path, ModuleDefinition? ownerModule, [NotNullWhen(true)] out PortablePdb? pdb)
21+
{
22+
MetadataDirectory metadata;
23+
try
24+
{
25+
metadata = MetadataDirectory.FromFile(path);
26+
}
27+
catch
28+
{
29+
pdb = null;
30+
return false;
31+
}
32+
33+
if (!TryFromMetadata(metadata, ownerModule, out pdb))
34+
return false;
35+
36+
pdb.FilePath = path;
37+
return true;
38+
}
39+
40+
public static bool TryFromBytes(byte[] bytes, ModuleDefinition? ownerModule, [NotNullWhen(true)] out PortablePdb? pdb)
41+
{
42+
MetadataDirectory metadata;
43+
try
44+
{
45+
metadata = MetadataDirectory.FromBytes(bytes);
46+
}
47+
catch
48+
{
49+
pdb = null;
50+
return false;
51+
}
52+
53+
return TryFromMetadata(metadata, ownerModule, out pdb);
54+
}
55+
56+
public static bool TryFromMetadata(MetadataDirectory metadata, ModuleDefinition? ownerModule, [NotNullWhen(true)] out PortablePdb? pdb)
57+
{
58+
if (!metadata.TryGetStream<PdbStream>(out var stream))
59+
{
60+
pdb = null;
61+
return false;
62+
}
63+
64+
pdb = new SerializedPortablePdb(metadata, ownerModule);
65+
return true;
66+
}
67+
68+
public ModuleDefinition? Owner { get; }
69+
70+
public byte[] PdbId { get; } = new byte[20];
71+
72+
public MetadataToken EntryPointToken { get; set; }
73+
74+
public MethodDefinition? EntryPoint { get; set; }
75+
76+
public string? FilePath { get; set; }
77+
78+
public IList<Document> Documents => _documents.GetValue(this);
79+
80+
public virtual bool TryLookupMember<T>(MetadataToken token, [NotNullWhen(true)] out T? member) where T : class, IMetadataMember
81+
{
82+
member = null;
83+
return false;
84+
}
85+
86+
protected virtual IList<Document> GetDocuments() => [];
87+
}
88+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
namespace AsmResolver.DotNet.PortablePdbs
2+
{
3+
public class SequencePoint
4+
{
5+
public const int HiddenLine = 0xfeefee;
6+
7+
public Document? Document { get; set; }
8+
public int Offset { get; set; }
9+
public int StartLine { get; set; }
10+
public int EndLine { get; set; }
11+
public int StartColumn { get; set; }
12+
public int EndColumn { get; set; }
13+
14+
public bool IsHidden => StartLine == HiddenLine && EndLine == HiddenLine && StartColumn == 0 && EndColumn == 0;
15+
}
16+
}

0 commit comments

Comments
 (0)