Generated PDB contains no imports and its ImportScope table has two roots
Summary
A PDB generated by ilspycmd -genpdb contains no imports at all, and its ImportScope table has two root rows instead of one. The debugger's expression evaluator resolves unqualified names through the import scope chain, so with such a PDB attached no using directive is in scope anywhere: List<int> or Task.Delay(1) fail to resolve in Watch / Immediate / conditional breakpoints, while the embedded source prominently shows the using directives they would need.
Reproduction
Probe.cs, compiled with the SDK so the compiler's own PDB is available as a reference:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace ProbeNs
{
public class Probe
{
public static async Task<int> MixedAsync(IEnumerable<int> source)
{
List<int> chunks = new List<int>();
foreach (int value in source)
chunks.Add(value);
await Task.Yield();
return chunks.Count;
}
}
}ilspycmd -genpdb Probe.dllImportScope table of the generated PDB:
r1: parent=nil imports=0
r2: parent=nil imports=0ImportScope table of the compiler's PDB for the same assembly:
r1: parent=nil imports=0
r2: parent=r1 imports=[System, System.Collections.Generic, System.Threading.Tasks]
r3: parent=r2 imports=0Every assembly checked shows the same shape (Newtonsoft.Json 13.0.4, AutoMapper 16.2.0, Microsoft.Extensions.Http 10.0.11).
Cause
In ICSharpCode.Decompiler/DebugInfo/DebugInfoGenerator.cs:
globalImportScope(line 45) is never added toimportScopes, soGenerateImportScopes(line 65) never encodes it and itsHandleis never assigned.- The decompiler prints all
usingdirectives at file level, before the namespace declaration, soVisitUsingDeclaration(line 96) adds every one of them tocurrentImportScope- which at that point is stillglobalImportScope. They are dropped. VisitNamespaceDeclaration(line 85) creates a scope whoseParentisglobalImportScope.scope.Parent == nullis therefore false andGenerateImportScopeswritesscope.Parent.Handle, the never-assigned handle, i.e. nil. The metadata-level global scope created inPortablePdbWriter.WritePdb(line 108) ends up orphaned and each namespace scope becomes a second root.
Posted by an AI agent (Claude) on Siegfried's behalf.
Source: icsharpcode/ILSpy