Debugger Method rewriting, localization of variable variables and variables

I am making a managed .NET debugger using an MDBG sample. It works for simple scripts, but has problems rewriting the method. Most critical parts are profitability and asynchronous methods.

I have already asked a more general question about these issues. Now I want to focus on solving local variables. Please pay attention to the code:

using System; using System.Threading.Tasks; class C { public static void Main() { var instance = new Instance(); instance.Start().Wait(); } } class Instance { public static async Task F() { for(var i=0; i<100; i++) { Console.WriteLine(i); await Task.Delay(100); } } public async Task Start() { var z = "test";<------- Breakpoint var x = 10; await F(); } } 

When the debugger reaches the breakpoint, I request the debugger to get local variables, and the only this variable. Variables x and z rise to the generated structure and cannot be resolved directly Picture .

So the question is: How to resolve local variables in the yield method and asynchronous methods while debugging?

In the comments on my previous question, @Brian Reichle gave me some tips on how I can get a mapping between an existing variable and a raised one. Studying SymAttribute and the Roslyn source, I came to the conclusion that it does not preserve a direct mapping between them. SymAttribute used to get CustomDebugInfoRecord , which stores some of this information (uses the Pdb2Xml library from Roslyn to create it):

  <method containingType="Instance+&lt;Start&gt;d__1" name="MoveNext"> <customDebugInfo> <forward declaringType="C" methodName="Main" /> <hoistedLocalScopes> <slot startOffset="0x0" endOffset="0xcc" /> <slot startOffset="0x0" endOffset="0xcc" /> </hoistedLocalScopes> <encLocalSlotMap> <slot kind="27" offset="0" /> <slot kind="33" offset="161" /> <slot kind="temp" /> <slot kind="temp" /> </encLocalSlotMap> </customDebugInfo> <sequencePoints> <entry offset="0x0" hidden="true" document="1" /> <entry offset="0x7" hidden="true" document="1" /> <entry offset="0xe" startLine="16" startColumn="37" endLine="16" endColumn="38" document="1" /> <entry offset="0xf" startLine="17" startColumn="14" endLine="17" endColumn="29" document="1" /> <entry offset="0x1a" startLine="18" startColumn="14" endLine="18" endColumn="35" document="1" /> <entry offset="0x26" startLine="19" startColumn="14" endLine="19" endColumn="25" document="1" /> <entry offset="0x2e" startLine="19" startColumn="25" endLine="19" endColumn="46" document="1" /> <entry offset="0x3a" startLine="20" startColumn="14" endLine="20" endColumn="24" document="1" /> <entry offset="0x45" hidden="true" document="1" /> <entry offset="0xa0" hidden="true" document="1" /> <entry offset="0xb8" startLine="21" startColumn="11" endLine="21" endColumn="12" document="1" /> <entry offset="0xc0" hidden="true" document="1" /> </sequencePoints> <asyncInfo> <kickoffMethod declaringType="Instance" methodName="Start" /> <await yield="0x57" resume="0x72" declaringType="Instance+&lt;Start&gt;d__1" methodName="MoveNext" /> </asyncInfo> </method> 

Thus, the only way that I can see now for resolving inserted variables is:

  • Check if the method is overwritten.
  • For such a method, get asyncInfo and look for it to declare declaringType. It gives the name of the structure that is generated and where the variables go up.
  • Solve this.generatedStructureName
  • Roslyn source code shows naming conventions for inverted variables that you can use to translate the variable x into <x>5__2

This approach seems wrong, and I'm not sure that it will ever work, but that is the only thing I can think of now. Is there any other way to solve this problem? How does VisualStudio handle this?

I created a small repo to reproduce the problem here

+5
source share
1 answer

Well, I have not found anyone here or on the msdn forums that would enlighten me on how the VS algorithm works, but I have found that SharpDevelop supports variable resolution for async methods. Surprisingly, he used a similar algorithm for what I described in his question: just parse the names of the displayed fields.

A linked source may be available here on gitHub if someone encounters similar issues and gets stuck. However, I do not think this is a good solution and I hope that there is a better way to solve the problem ...

+1
source

All Articles