-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
BrowserDebugProxy: unify debug metadata reading for PE and Webcil (#8…
…1099) * DebugStore: factor common PE and Webcil reading logic * Move common logic to a MetadataDebugSummary class Also switch from cascade of 'if's to a 'switch' when looking at debug entries * Implement PDB checksum reader for WebcilReader * Move WebcilReader reflection to a helper; add lazy initialization Co-authored-by: Ankit Jain <[email protected]>
- Loading branch information
1 parent
4a156cc
commit d92e70f
Showing
7 changed files
with
284 additions
and
105 deletions.
There are no files selected for viewing
59 changes: 59 additions & 0 deletions
59
src/libraries/Microsoft.NET.WebAssembly.Webcil/src/Webcil/WebcilReader.Reflection.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System; | ||
using System.Collections.Immutable; | ||
using System.IO; | ||
using System.Reflection; | ||
using System.Runtime.InteropServices; | ||
|
||
using System.Reflection.Metadata; | ||
using System.Reflection.PortableExecutable; | ||
|
||
namespace Microsoft.NET.WebAssembly.Webcil; | ||
|
||
|
||
public sealed partial class WebcilReader | ||
{ | ||
|
||
// Helpers to call into System.Reflection.Metadata internals | ||
internal static class Reflection | ||
{ | ||
private static readonly Lazy<MethodInfo> s_readUtf8NullTerminated = new Lazy<MethodInfo>(() => | ||
{ | ||
var mi = typeof(BlobReader).GetMethod("ReadUtf8NullTerminated", BindingFlags.NonPublic | BindingFlags.Instance); | ||
if (mi == null) | ||
{ | ||
throw new InvalidOperationException("Could not find BlobReader.ReadUtf8NullTerminated"); | ||
} | ||
return mi; | ||
}); | ||
|
||
internal static string? ReadUtf8NullTerminated(BlobReader reader) => (string?)s_readUtf8NullTerminated.Value.Invoke(reader, null); | ||
|
||
private static readonly Lazy<ConstructorInfo> s_codeViewDebugDirectoryDataCtor = new Lazy<ConstructorInfo>(() => | ||
{ | ||
var types = new Type[] { typeof(Guid), typeof(int), typeof(string) }; | ||
var mi = typeof(CodeViewDebugDirectoryData).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, types, null); | ||
if (mi == null) | ||
{ | ||
throw new InvalidOperationException("Could not find CodeViewDebugDirectoryData constructor"); | ||
} | ||
return mi; | ||
}); | ||
|
||
internal static CodeViewDebugDirectoryData MakeCodeViewDebugDirectoryData(Guid guid, int age, string path) => (CodeViewDebugDirectoryData)s_codeViewDebugDirectoryDataCtor.Value.Invoke(new object[] { guid, age, path }); | ||
|
||
private static readonly Lazy<ConstructorInfo> s_pdbChecksumDebugDirectoryDataCtor = new Lazy<ConstructorInfo>(() => | ||
{ | ||
var types = new Type[] { typeof(string), typeof(ImmutableArray<byte>) }; | ||
var mi = typeof(PdbChecksumDebugDirectoryData).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, types, null); | ||
if (mi == null) | ||
{ | ||
throw new InvalidOperationException("Could not find PdbChecksumDebugDirectoryData constructor"); | ||
} | ||
return mi; | ||
}); | ||
internal static PdbChecksumDebugDirectoryData MakePdbChecksumDebugDirectoryData(string algorithmName, ImmutableArray<byte> checksum) => (PdbChecksumDebugDirectoryData)s_pdbChecksumDebugDirectoryDataCtor.Value.Invoke(new object[] { algorithmName, checksum }); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 24 additions & 0 deletions
24
src/mono/wasm/debugger/BrowserDebugProxy/IDebugMetadataProvider.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
#nullable enable | ||
|
||
using System; | ||
using System.Collections.Immutable; | ||
using System.Reflection.Metadata; | ||
using System.Reflection.PortableExecutable; | ||
|
||
namespace Microsoft.WebAssembly.Diagnostics; | ||
|
||
/// <summary> | ||
/// An adapter on top of MetadataReader and WebcilReader for DebugStore compensating | ||
/// for the lack of a common base class on those two types. | ||
/// </summary> | ||
public interface IDebugMetadataProvider | ||
{ | ||
public ImmutableArray<DebugDirectoryEntry> ReadDebugDirectory(); | ||
public CodeViewDebugDirectoryData ReadCodeViewDebugDirectoryData(DebugDirectoryEntry entry); | ||
public PdbChecksumDebugDirectoryData ReadPdbChecksumDebugDirectoryData(DebugDirectoryEntry entry); | ||
|
||
public MetadataReaderProvider ReadEmbeddedPortablePdbDebugDirectoryData(DebugDirectoryEntry entry); | ||
} |
89 changes: 89 additions & 0 deletions
89
src/mono/wasm/debugger/BrowserDebugProxy/MetadataDebugSummary.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
#nullable enable | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Collections.Immutable; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Reflection.Metadata; | ||
using System.Reflection.PortableExecutable; | ||
using System.Threading; | ||
using Microsoft.FileFormats.PE; | ||
|
||
namespace Microsoft.WebAssembly.Diagnostics; | ||
|
||
/// <summary> | ||
/// Information we can extract directly from the assembly image using metadata readers | ||
/// </summary> | ||
internal sealed class MetadataDebugSummary | ||
{ | ||
internal MetadataReader? PdbMetadataReader { get; private init; } | ||
internal bool IsPortableCodeView { get; private init; } | ||
internal PdbChecksum[] PdbChecksums { get; private init; } | ||
|
||
internal CodeViewDebugDirectoryData? CodeViewData { get; private init; } | ||
|
||
private MetadataDebugSummary(MetadataReader? pdbMetadataReader, bool isPortableCodeView, PdbChecksum[] pdbChecksums, CodeViewDebugDirectoryData? codeViewData) | ||
{ | ||
PdbMetadataReader = pdbMetadataReader; | ||
IsPortableCodeView = isPortableCodeView; | ||
PdbChecksums = pdbChecksums; | ||
CodeViewData = codeViewData; | ||
} | ||
|
||
internal static MetadataDebugSummary Create(MonoProxy monoProxy, SessionId sessionId, string name, IDebugMetadataProvider provider, byte[]? pdb, CancellationToken token) | ||
{ | ||
var entries = provider.ReadDebugDirectory(); | ||
CodeViewDebugDirectoryData? codeViewData = null; | ||
bool isPortableCodeView = false; | ||
List<PdbChecksum> pdbChecksums = new(); | ||
DebugDirectoryEntry? embeddedPdbEntry = null; | ||
foreach (var entry in entries) | ||
{ | ||
switch (entry.Type) | ||
{ | ||
case DebugDirectoryEntryType.CodeView: | ||
codeViewData = provider.ReadCodeViewDebugDirectoryData(entry); | ||
if (entry.IsPortableCodeView) | ||
isPortableCodeView = true; | ||
break; | ||
case DebugDirectoryEntryType.PdbChecksum: | ||
var checksum = provider.ReadPdbChecksumDebugDirectoryData(entry); | ||
pdbChecksums.Add(new PdbChecksum(checksum.AlgorithmName, checksum.Checksum.ToArray())); | ||
break; | ||
case DebugDirectoryEntryType.EmbeddedPortablePdb: | ||
embeddedPdbEntry = entry; | ||
break; | ||
default: | ||
break; | ||
} | ||
} | ||
|
||
MetadataReader? pdbMetadataReader = null; | ||
if (pdb != null) | ||
{ | ||
var pdbStream = new MemoryStream(pdb); | ||
try | ||
{ | ||
// MetadataReaderProvider.FromPortablePdbStream takes ownership of the stream | ||
pdbMetadataReader = MetadataReaderProvider.FromPortablePdbStream(pdbStream).GetMetadataReader(); | ||
} | ||
catch (BadImageFormatException) | ||
{ | ||
monoProxy.SendLog(sessionId, $"Warning: Unable to read debug information of: {name} (use DebugType=Portable/Embedded)", token); | ||
} | ||
} | ||
else | ||
{ | ||
if (embeddedPdbEntry != null && embeddedPdbEntry.Value.DataSize != 0) | ||
{ | ||
pdbMetadataReader = provider.ReadEmbeddedPortablePdbDebugDirectoryData(embeddedPdbEntry.Value).GetMetadataReader(); | ||
} | ||
} | ||
|
||
return new MetadataDebugSummary(pdbMetadataReader, isPortableCodeView, pdbChecksums.ToArray(), codeViewData); | ||
} | ||
} |
Oops, something went wrong.