托管.NET调试器和async / await方法

时间:2016-08-22 11:24:06

标签: c# debugging asynchronous cil mdbg

我正在使用MDBG示例制作托管.NET调试器。

考虑一些简单的异步示例:

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:         }

使用我的调试器调试此代码我遇到了两个主要问题:

  1. 本地变量名称已更改(CS $ 4 $ 0000,CS $ 0 $ 0001,等等)或缺失(无法在调试器的本地变量中找到obj)
  2. 步进行为不可预测: a) 单步执行第3行等等通常应在等待评估完成后转到第4行。但是调试器跳转到第13行并继续从那里踩到。 StepOver behaviour on video

    b) 步入第3行,依此类推,只需踩到每一行:第3行 - &gt;第12行 - &gt;第13行(暂停一段时间) - &gt;第14行 - &gt;第15行 - &gt;然而,在第13行进入后,我希望调试器等待评估结果,由于某种原因,步进继续到第3行。之后,调试器等待结果并按预期继续执行。 StepIn behaviour on video

    c)如果在等待响应时安排了其他一些工作,调试器会切换到该代码。例如,如果在等待响应期间有一些计时器,则在第13行之后继续对该计时器代码进行评估。相反,像visual studio一样,我希望调试器能够坚持使用它的当前范围,并且在它完全执行之前不要离开它。 Parallel behaviour on video

  3. 部分我理解这些问题的根源:编译器创建一个由嵌套结构表示的状态机,其中逻辑封装在MoveNext方法中。这至少解释了为什么步进不能像我期望的情况a)和b)那样工作。当我踩到一些没有符号的代码时(我没有编译器生成的代码符号),我做了一个或多个步骤来获取我的一些代码。这是@Brian Reichle在this related question

    中提出的解决方案

    关于本地变量名称的更改我认为它因Stack Spilling("What's happening" chapter)而发生。但是用ILDASM分析我的程序集我还没有发现任何保存到生成结构的t__stack字段的内容。因此,我猜测为什么变量名不会因异步方法而持久存在。

    然而,VisualStudio以某种方式避免了所有这些问题。

    那么托管.net调试器应如何处理异步/等待场景中的步进和局部变量解析?

    这背后有很多实现代码,但我不确定哪个部分合理显示...

0 个答案:

没有答案