.NET Managed Debugger and async / wait Methods

I am making a managed .NET debugger using an MDBG sample.

Consider an example of a simple asynchronous procedure:

1: private async void OnClick(EventArgs args){ 2: var obj = new SomeClass(); 3: bool res = await StaticHelper.DoSomeAsyncStuff(); 4: if(res){ 5: Debug.WriteLine("result is True"); 6: } 7: else{ 8: Debug.WriteLine("result is False"); 9: } 10: someField = obj.Name + "is:" + res.ToString(); 11: } 12: public static async Task<bool> DoSomeAsyncStuff(){ 13: await Task.Delay(5000); 14: return true; 15: } 

Debugging this code with my debugger. I encounter two main problems:

  • Names of local variables changed (CS $ 4 $ 0000, CS $ 0 $ 0001, ect) or missing (cannot find obj in local variables of the debugger)
  • The steps behave unpredictably: a) Step on line 3, etc. usually go to line 4 after waiting for the assessment to complete. But instead, the debugger goes to line 13 and continues to back out. StepOver Behavior on Video

    b) Entering line 3, etc. should just step on each line: line 3 β†’ line 12 β†’ line 13 (hang for a while) β†’ line 14 β†’ line 15 β†’ line 4. But instead of going to line 13, where I expect the debugger to wait for the result of the evaluation, by for some reason, the stepping continues to line 3. After that, the debugger waits for the result, and execution continues as expected. StepIn Behavior on Video

    c) If another work is being performed while waiting for a response, the debugger switches to this code. For example, if there is a timer that has expired while waiting for a response, the evaluation after line 13 continues with this timer code. Instead, like visual studio, I expect the debugger to stick to the current area and not leave it until it is fully executed. Parallel behavior on video

In part, I understand the source of these problems: the compiler creates a state machine, which is represented by a nested structure where the logic is encapsulated inside the MoveNext method. This, at least, explains to me why the step does not work, as I would expect for case a) and b). When I enter some code without characters (and I don't have characters for the code generated by the compiler), I take one or more steps to get to some of my code. This is the solution that @Brian Reichle suggested in this related question

As for changing the names of local variables, I thought this was due to Stack Spilling (β€œWhat's happening”) . But, while analyzing my build with ILDASM, I did not find anything in the t__stack field of the generated structure. Therefore, I do not understand why variable names are not stored for asynchronous methods.

Nevertheless, VisualStudio somehow avoided all these problems.

So, how should a managed .net debugger handle stepping and local change of variables in an asynchronous / pending scenario?

There is a lot of implementation code behind this, but I'm not sure which part would be reasonable to show ...

+2
source share

All Articles