Skip to content

Cecil fails to load portable pdb files for crossgen'd assemblies #704

@eerhardt

Description

@eerhardt

See dotnet/linker#1620 (comment) for more context.

Using the following code:

				ISymbolReaderProvider _symbolReaderProvider = ...;
				AssemblyDefinition assembly = ...;

				var symbolReader = _symbolReaderProvider.GetSymbolReader (
					assembly.MainModule,
					fileName);

				assembly.MainModule.ReadSymbols (symbolReader);

When the AssemblyDefinition assembly points to a crossgen'd assembly, fails to load the symbols in a portable pdb file.

The reason it fails is because a cross gen'd assembly's Debug Directories has two entries:

>dumpbin /headers C:\Users\eerhardt\.nuget\packages\microsoft.netcore.app.runtime.win-x64\5.0.0-rtm.20508.7\runtimes\win-x64\lib\net5.0\System.Private.Xml.dll

Debug Directories

        Time Type        Size      RVA  Pointer
    -------- ------- -------- -------- --------
    8B4C3C7E cv           11C 00801444   800044    Format: RSDS, {2E2D2AB8-5EC5-3956-8E87-3741A2D79E30}, 1, System.Private.Xml.ni.pdb
    8B4C3C7E cv            77 00801560   800160    Format: RSDS, {62DF6790-3B25-4522-8E89-99FB491C298D}, 1, F:\git\runtime2\artifacts\obj\System.Private.Xml\net6.0-windows-Release\System.Private.Xml.pdb
    00000000 repro          0 00000000        0

And the 2nd entry is the portable pdb entry.

However, ModuleDefinition.ReadSymbols appears to only look at the first entry in the Debug Directories and it throws an exception when the first entry doesn't match the portable pdb's Guid. See the following code:

if (!symbol_reader.ProcessDebugHeader (GetDebugHeader ())) {
symbol_reader = null;
if (throwIfSymbolsAreNotMaching)
throw new SymbolsNotMatchingException ("Symbols were found but are not matching the assembly");

and

public bool ProcessDebugHeader (ImageDebugHeader header)
{
if (image == module.Image)
return true;
var entry = header.GetCodeViewEntry ();
if (entry == null)
return false;
var data = entry.Data;
if (data.Length < 24)
return false;
var magic = ReadInt32 (data, 0);
if (magic != 0x53445352)
return false;
var buffer = new byte [16];
Buffer.BlockCopy (data, 4, buffer, 0, 16);
var module_guid = new Guid (buffer);
Buffer.BlockCopy (image.PdbHeap.Id, 0, buffer, 0, 16);
var pdb_guid = new Guid (buffer);
if (module_guid != pdb_guid)
return false;
ReadModule ();
return true;
}

Cecil should continue iterating the list and discover the 2nd entry and match it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions