【问题标题】:In Delphi: How to skip sections of code while debugging?在 Delphi 中:如何在调试时跳过代码段?
【发布时间】:2009-01-16 01:08:49
【问题描述】:

在 Delphi 中调试时,我经常不小心进入我不感兴趣的代码。

先说我知道你可以按F8跨过去,按f4可以跑到某一行。

例子:

function TMyClass.DoStuff():Integer;
begin
  // do some stuff
  bla();
end;

procedure TMyClass.Foo()
begin
  if DoStuff()=0 then // press F7 when entering this line
    beep;
end;

示例:我想通过按 F7 进入方法 DoStuff(),但我没有去那里,而是首先进入 FastMM4.FastGetMem(),这是一个明显我不感兴趣的大量汇编代码目前在中。

有几种方法可以解决这个问题,我不喜欢其中任何一种:

  • 在“bla”上添加断点(如果你只想在特殊情况下进入 DoStuff,几乎没用,比如迭代 23498938);

  • 不要按 F7,而是手动将光标移动到“bla”,然后按 F4(适用于这个简单的示例。实际上,它不会);

  • 在 FastMM 的情况下:暂时禁用 fastmm;

有什么方法可以提示 IDE 我从不有兴趣进入某个代码块,还是我总是必须设置额外的断点或使用 F4 来避免这种情况?

我希望有一些神奇的编译器指令,例如 {$NODEBUG BEGIN/END} 或类似的东西。

在大多数情况下,能够排除整个单元对我来说足够细粒度,但能够避免某些方法甚至代码行会更好。

更新:也许 codegear 应该引入类似 skip-points 的东西(而不是断点):-)

【问题讨论】:

    标签: delphi debugging


    【解决方案1】:

    有一个“神奇的 nodebug 开关”。 {$D-} 将禁用调试代码的生成。把它放在你的 FastMM 单元的顶部,你最终不会追踪到它。如果你最终进入了一个你不想进入的功能,SHIFT-F8 会让你很快离开。 (警告:不要在使用堆栈的汇编代码例程中使用 SHIFT-F8。可能会导致不可预测的行为。改为 F4 到它的底部。)

    【讨论】:

    • 太棒了!它完全按照我想要的方式工作:调试器不再介入它,同时仍然可以完成代码,并且能够查看和修改“debug-disabled”代码,如果我愿意的话。
    • 至于 FastMM4:泄漏报告仍然有效,只要您没有默认未定义的 {$define RequireDebugInfoForLeakReporting}。
    • 您先生,就我而言,今天赢得了互联网。工作得很漂亮。非常非常感谢。
    【解决方案2】:

    如果您要跳入 FastMM 代码,那么就会发生内存操作。您显示的代码没有任何内存操作,因此您的问题不完整。我会试着猜测你的意思。

    当子例程具有编译器管理类型的局部变量(例如字符串、接口或动态数组)时,函数序言有非常重要的工作要做。序言也是调整输入参数的引用计数的地方。调试器代表函数begin 行中的序言。如果当前执行点是该行,并且您“进入”它,您将被带到用于管理特殊类型的 RTL 代码。 (我也不希望 FastMM 参与其中,但也许事情已经改变了我以前的习惯。)在这种情况下,一件容易做的事情是“跨过”begin 行而不是进入它;使用 F8。

    如果您在进入突出显示的行时确实按了 F7,那么您做错了。这是进入begin 行,不是调用DoStuff 的行。因此,您是否被 FastMM 代码所吸引与 DoStuff 的实现无关。要调试对DoStuff 的调用,当前执行点应该已经是调用所在的行。

    如果您只想在迭代 23498938 上调试 DoStuff,那么您可以在该函数中设置一个条件断点。在装订线中单击以创建一个正常的断点,然后右键单击它以显示其属性。在那里,您可以定义一个条件,每次执行到达该点时都会评估该条件。调试器只会在条件为真时停止。按 F8 以“跳过”DoStuff 调用,如果条件为真,调试器将停在那里,就像您按 F7 一样。

    您可以切换“使用调试 DCU”选项以避免进入大多数 RTL 和 VCL 单元。我不知道 FastMM 是否包含在该集合中。主要区别在于您链接到的 DCU 是否使用调试信息进行编译。该设置会更改 库路径 以包含或排除调试 DCU 所在的子目录。我认为您可以配置包含或排除的调试目录集,以便根据“调试 DCU”设置添加或删除自定义目录集。

    返回断点。您可以通过为断点指定名称来设置断点组。您可以使用高级断点在传递时启用或禁用一组命名的断点。 (如果需要,断点组可以只有一个断点。)因此,例如,如果您只想在位置 X 中断,如果您还通过了程序中的某个其他位置 Y,则可以在 X 处设置禁用断点在 Y 处设置一个非中断断点。在 Y 处设置“启用组”设置以启用组 X。

    您还可以利用已禁用的断点,而无需自动启用和禁用。您的断点出现在“断点”调试器窗口中。如果您正在单步执行DoStuff,并且决定这次要检查bla,请转到断点窗口并在bla 处启用断点。无需导航到 bla 的实现即可在此处设置断点。

    有关高级断点的更多信息,请参阅Using Non-Breaking Breakpoints in Delphi,以及 Cary Jensen 几年前的文章。

    【讨论】:

    • >>...因此根据“调试 DCU”设置添加或删除客户目录集。
    • 你是对的,这个例子很弱,因为 FastMM 特定的问题不会在那里发生。我怀疑是否接受这个答案或梅森的。这个答案充满了有趣的信息和提示,但梅森的答案立即解决了问题。
    【解决方案3】:

    我可能在您的帖子中遗漏了一些内容,但使用 FastMM4,您可以编辑 FastMM4Options.Inc 包含文件并删除“。”从以下定义:


    来自 FastMM4Options.inc ****

    {启用此选项以禁止生成调试信息 FastMM4.pas 单元。这将阻止集成调试器进入 内存管理器代码。}

    {$.define NoDebugInfo}


    在重新编译(可能需要构建)时,调试器将(应该)不再调试 FastMM 代码。

    【讨论】:

    • (+1) 尽管 fastmm 仅用作示例,但我认为您的建议是照顾 fastmm4 的最佳方法。修改 fastmm4.pas 感觉有点不对;
    【解决方案4】:

    使用 FasmMM 的预编译非调试 DCU

    【讨论】:

      【解决方案5】:

      在项目dpr文件中,我使用

      uses
      {$IFNDEF DEBUG} FastMM4, {$ENDIF}
        ... // other units
      

      在调试模式下排除 FastMM4。不需要在 FastMM4 中进行任何更改,因此当我更改为其他版本时,我不必记得在 FastMM 中添加 {$D-}。

      【讨论】:

        【解决方案6】:

        AFAIK,调试器只知道您可以在选项中修改的浏览路径中的文件。因此,如果您排除您对调试不感兴趣的模块的路径,这将产生您想要做的效果。

        一个警告:代码完成还依赖于浏览路径,因此您可能会遇到代码完成在需要时不足的情况。

        【讨论】:

          【解决方案7】:

          虽然它不是您问题的直接答案,但您可以通过将断点置于 bla 来修改您的第一个建议解决方案,该断点仅在通过 Foo 处的断点时启用(或您选择的其他一些条件,例如迭代数数)。然后它只会在你想要的时候打破。

          顺便说一句,我越来越发现我不是在断点处停止执行,而是将变量值或堆栈转储转储到消息日志中。这允许比动态检查变量等更仔细的分析。FWIW。

          【讨论】:

            【解决方案8】:

            没有。我不相信有一种方法可以告诉调试器永远不要在代码的某个部分停止。没有魔法指令。

            当你进入一个你不想进入的例程时,你能做的最好的事情就是使用 Shift+F8,它会一直运行到返回。然后按 F7 或 F8 退出程序。


            嗯。现在我看到了梅森的回答。学到了一些东西。谢谢,梅森。 +1

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2021-05-09
              • 2018-05-13
              • 1970-01-01
              • 2013-12-19
              • 2012-01-18
              • 2013-12-27
              • 2012-09-25
              相关资源
              最近更新 更多