ILSpy icon indicating copy to clipboard operation
ILSpy copied to clipboard

Add tests for PDBGen

Open siegfriedpammer opened this issue 4 years ago • 4 comments

We need tests for PDBGen:

These could be similar to existing IL pretty tests:

  1. Take IL and fixed list of sequence points
  2. Decompile + Generate PDB
  3. Compare output + list of sequence points

siegfriedpammer avatar Apr 10 '20 21:04 siegfriedpammer

Hi, I'm looking into whether I am capable of adding these tests and was contemplating the most effective ways of ensuring the tests provide the best possible coverage. My initial thought is that the tests should take existing DLLs of various open-source projects (such as Json.NET, Cecil, etc, used in the round-trip tests), decompile them, generate sequence points, and then compare the generated sequence points with the ones in the original PDB.

Because I understand that the generated sequence points are only an approximation, I think I won't be able to compare them directly, as that would likely yield way too many false positives. I was wondering if, instead, I could use some high-level heuristics to detect that something is wrong and may negatively effect the stepping experience, such as:

  • If two call / callvirt instructions were in the same sequence point in the original pdb, but aren't in the same sequence point in the generated PDB
  • If there is are two (or more) sequence points in the original PDB which are wholly contained inside a single generate sequence point

Before I attempt to go on this endeavor, I would love to get your feedback both on the general approach and on the heuristics listed above. Thanks for listening!

/cc @dgrunwald

OmerRaviv avatar Jan 13 '21 11:01 OmerRaviv

The sequence points original PDB are a mapping between IL-Offsets and the original source code. The sequence points in the ILSpy-generated PDB is a mapping between IL-Offsets and the decompiled source code. Because the source code isn't identical (different line numbers; potentially different arrangement of control flow (e.g. early-return vs. else-block)), the sequence points won't be identical either.

The other option is to decompile a DLL, then recompile it with the C# compiler. Now you have two PDBs referring to the same source code, but to different assemblies. The IL offsets won't be the same, so you also won't get comparable sequence points.

Even the checks you suggest don't work. Consider the original source code:

int i = FirstCall();
Console.WriteLine(i);

The C# compiler may optimize out the local variable i, the the decompiled code now looks like this:

Console.WriteLine(FirstCall());

So for the decompiled PDB both calls are in the same sequence point, whereas they aren't in the original PDB.

I guess your approach can work if you compare two PDBs that both apply to the same source code (ILSpy-generated PDB and PDB generated when recompiling the decompiled code) -- you can match sequence points based on their line numbers. They will have different IL offsets associated with them, but you could look into the associated IL code and check that the set of call instructions matches. There will probably still be some differences; especially if the original assembly was compiled by a different Roslyn version than the recompiled assembly (e.g. different implementations of string concatenation). But maybe at least the simple case where the same compiler was used for the original compilation and the recompilation can be made to work.

Still, this is only a sanity check (like our RoundtripTests are for the decompiler), we definitely also need unit tests where we can check specific problematic code constructs.

dgrunwald avatar Jan 13 '21 16:01 dgrunwald

Regarding constructs and feature status please also see #1422 and #1901

christophwille avatar Jan 13 '21 16:01 christophwille

I added another test in https://github.com/icsharpcode/ILSpy/pull/3032, currently disabled

KirillOsenkov avatar Jul 02 '23 00:07 KirillOsenkov