Quantcast
Channel: Common Language Runtime Internals and Architecture forum
Viewing all articles
Browse latest Browse all 1710

Debugger Engine. Method rewriting, local variables hoisting and variables resolution

$
0
0

I'm making a managed .NET debugger using MDBG sample. It works for straightforward scenarios, but has issues when method rewriting occurs. Most critical parts are yield method and async methods.

I want to focus on local variables resolution. Please consider the code:

    using System;
    using System.Threading.Tasks;class C{publicstaticvoidMain(){var instance =newInstance();
            instance.Start().Wait();}}classInstance{publicstatic async Task F(){for(var i=0; i<100; i++){Console.WriteLine(i); await Task.Delay(100);}}public async TaskStart(){var z ="test";<-------Breakpointvar x =10;
           await F();}}

When debugger reaches Breakpoint I'm querying debugger to get local variables and the only variable isthis. Variables x and z are hoisted on generated structure and cannot be resolved directly .

So the question is: How to resolve during debug local variables in yield method and async methods?

In comments to my previous question @Brian Reichle gave me some hints how I can get mapping between existing variable and hoisted one. Exploring SymAttribute and Roslyn source I came to conclusion that it doesn't directly store mapping between them.SymAttribute is used to get CustomDebugInfoRecord, which stores part of this information(Used Pdb2Xml library from Roslyn to generate 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>

So the only way I can see now to resolve hoisted variables is:

  1. Check if method is rewritten.
  2. For such method get asyncInfo and find it's await declaringType. It gives the name of structure that is generated and where the variables are hoisted.
  3. Resolve this.generatedStructureName
  4. Roslyn source code reveals naming conventions for hoisted variables, that can be used to translatex variable into <x>5__2

This approach doesn't seems right and I'm not sure if it will ever work out, but it's the only thing I can think of now. Is there any other possibility to solve this problem? How does VisualStudio tackle it?

I've created a small repo to reproduce the problem, but I cannot post the link...


Viewing all articles
Browse latest Browse all 1710

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>