【问题标题】:Release resource during debug break (C++, MSVC)在调试中断期间释放资源(C++、MSVC)
【发布时间】:2016-02-29 11:03:30
【问题描述】:

当程序在调试器中停止时,是否可以释放资源(文件锁、计时器)?

更一般地说,我可以在 MSVC 停止程序进行调试之前和恢复执行之后执行代码吗?

我想完成的事情: - 在调试期间自动释放文件锁定以进行编辑。 - 进程恢复后自动重新加载文件 - 防止定时器在调试停止期间触发溢出 - 从计时器中减去调试所花费的持续时间

解决方法:如果在程序被调试器停止之前我无法执行代码,那么在程序中以编程方式检测调试器停止了应用程序已经很有帮助。


编辑: 我查看了用于调试器集成的 Windows API 函数,但似乎 ContinueDebugEvent 之类的函数仅适用于调试器的编写者,而不适用于被调试的进程。


编辑 2: 似乎对 DbgBreakPoint 函数进行热修补可能是一种在 Debugger 想要中断进程时进行拦截的方法。

附加的主要思想是调试器调用 “DebugActiveProcess”函数最终调用 “RtlCreateUserThread”函数创建一个新的远程线程进入 目标进程,以“DbgUiRemoteBreakin”函数为新 线程入口点。

(来自http://waleedassar.blogspot.de/2011/12/debuggers-anti-attaching-techniques.html

DbgUiRemoteBreakin 似乎调用 DbgBreakPoint 来实际停止进程。


编辑 3: 我对 DbgBreakPoint 和 DebugBreak 进行了热补丁,以查看当我以交互方式中断时是否从 MSVC 调试器调用这些方法。唉,他们没有!似乎 MSVC 调试器只是在断点位置插入 int 3 而没有调用任何处理方法。


编辑 4: 阅读结构化异常及其与 DebugBreak 陷阱的交互也会导致死路:当遇到断点时,中断 3 将首先到达内核,内核首先将结构化异常传递给调试器(如果附加)。调试器处理中断,而应用程序永远不会看到它。

【问题讨论】:

  • 你认为断点条件有用吗。 msdn.microsoft.com/library/7sye83ce(v=vs.100).aspx
  • 并非如此。断点条件在被调试的进程中不可见。
  • @HansPassant:对于每个用户来说,使用中间窗口是一种手动过程。我宁愿编写代码将行为直接放入应用程序中。
  • 如果你不知道它是如何工作的,那么我猜任何事情都是可能的。 C++ 需要一个编译器和一个链接器,它们没有内置在调试器中。您必须在调试之前编写该代码。只要确保您可以从即时窗口轻松调用它。您也忽略了好的建议,在您的代码中使用 IsDebuggerPresent() 是个好主意。只需使用很长的超时时间,并且在文件返回 TRUE 时不要锁定文件。编写可调试的代码与编写正确的代码一样重要。

标签: c++ debugging visual-c++ timer


【解决方案1】:

免责声明:我自己使用单元测试而不是使用调试器进行如此深入的黑客攻击,但永远不要说永远。

是否可以在程序运行时释放资源(文件锁) 在调试器中停止?

调试器不包含此类功能。最简单的是使用Process Explorer 或其他类似的工具。但是,如果您继续 此后程序不再释放资源,后续访问这些资源的尝试将失败。

更一般地说,我可以在 MSVC 停止程序之前执行代码吗 用于调试和恢复执行后?

您可以临时编辑您的代码,以在您计划在调试器中中断代码之前和之后执行您希望它执行的任何操作。只是不要忘记稍后删除这些临时代码。您还可以通过强制setting the next statement to execute 来编辑数据内容,甚至更改代码的执行顺序,但这很难正确做到。

我的程序锁定了一个文件,我想在调试期间交换它。

还有一个选项,在您使用OF_SHARE_DENY_NONE 标志打开调试时不锁定文件。

【讨论】:

    【解决方案2】:

    这并不漂亮,但假设您没有设置优化标志,请在相关点添加如下内容。

    bool executeMe = false;
    
    if(executeMe) {
        // Code to release lock / close file ...
    }
    
    // ... normal code
    

    现在只需在此之前中断,并在评估减速之后和评估 if 语句之前在调试器局部变量视图中将 executeMe 变量设置为 true。

    编辑:计时器要求等。可以通过记录中断点之前的时间并在退出调试块后使用上述语句将计时器调回来类似地满足要求。

    编辑:

    WRT 自动化,为什么不在程序中嵌入触发断点的条件,并在调用 __debugbreak() 之前进行设置?您使用的条件可能是程序内部的,也可能是存在以下触发器文件之类的东西。

    bool debugging = false;
    
    struct stat unused;
    if(!stat('.\\.debugflag',&unused)) {
        // Release locks, Close files, Stop timers .etc.
        // ...
        // Hook debuger. At this point you should be right to debug
        debugging = true;
        __debugbreak();  
    }
    
    // Code to debug ....
    
    if(debugging) {
        // Cleanup after debug
    }
    

    【讨论】:

    • 这必须是自动的,我们有10个这样的东西,一旦调试器被命中就需要管理。
    【解决方案3】:

    我还不能评论,所以对其他答案表示歉意。

    在 MS Visual Studio 中,您可以使用 API 调用检测您的应用程序是否在调试器下运行

    BOOL WINAPI IsDebuggerPresent(void);
    

    来自 MSDN:https://msdn.microsoft.com/en-us/library/windows/desktop/ms680345%28v=vs.85%29.aspx

    根据 Jara 的回答,我看不出有什么方法可以编写自己的锁定。

    【讨论】:

    • 如果调试器停止/恢复进程,IsDebuggerPresent() 无助于触发某些代码。
    • 正如我在文中所说的那样。
    【解决方案4】:

    你写一个这样的函数怎么样

    void break( resource r1)
    {
       release resource;
       throw false;
       rebind resource;
    }
    

    您调用 break 函数而不是使用普通断点,该函数会释放资源并引发 bool 异常。鉴于您的程序不处理布尔异常,您的 MSVC 调试器将捕获它并为您提供中断选项。然后你可以编辑文件/做任何事情,一旦你完成你点击恢复,资源将被反弹。

    这显然不能让您在运行时交互式设置断点,但也许有帮助

    【讨论】:

      【解决方案5】:

      如何使用 SetUnhandledExceptionFilter 为您检查中断 3(调试断点)的进程安装全局处理程序?

      处理程序可以释放锁,然后继续执行 EXCEPTION_CONTINUE_SEARCH,实质上是将断点中断传递给调试器?

      您可以通过查看 EXCEPTION_RECORD::ExceptionCode == EXCEPTION_BREAKPOINT 来区分断点

      【讨论】:

      • 不起作用,因为调试器会先捕获 int 3。
      【解决方案6】:

      除了编写自己的调试器或修补 Visual Studio 之外,我看到的唯一其他解决方案是扫描所有代码页(标有执行位)以查找 0xCC 字节(int 3 指令)并通过跳转/调用来修补它们释放资源的函数,然后是 DebugBreakpoint()。

      为了确定 0xCC 是 int3 指令还是较长操作码的一部分,您需要反汇编整个应用程序/dll 或复制所有代码页,以便比较引入的 0xCC 更改由调试器。您也许可以使用 QueueUserAPC() 触发代码页扫描,因为调试器会在放置 int3 后向您的线程发出信号以恢复执行,让您有机会在您的应用程序之前用跳转到我的函数指令替换 int3命中 int3。

      编辑:您不需要复制所有代码页,只需复制出现在可执行页中的所有 0xCC 字节的地址即可。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-02-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-08
        • 2012-05-04
        • 1970-01-01
        相关资源
        最近更新 更多