【问题标题】:how to use visual studio debugging sub process?如何使用visual studio调试子流程?
【发布时间】:2018-07-12 15:50:17
【问题描述】:

我想调试一个由进程 A 启动的进程 B,当我连接进程 B 时出现错误,我无法在主函数上中断。有没有办法在进程 B 启动时自动中断?

【问题讨论】:

    标签: windows visual-studio debugging visual-c++


    【解决方案1】:

    不幸的是,视觉工作室没有办法。起初和主要 - 这个调试器不能一次调试多个进程。它只能调试一个进程。如果您调试进程 A 并且它启动了进程 B - 此调试器根本无法调试新进程 B

    通常当我们调试进程时A - 存在附加到进程的DebugPort 对象。 ( EPROCESS.DebugPort ) 在 EPROCESS 对象中也存在 NoDebugInherit 标志。当进程 A 启动新进程 B - 系统下一步(伪代码):

    if (Process->DebugPort && !Process->NoDebugInherit) 
        AttachDebugPortToNewProcess(Process->DebugPort);
    

    如果 A 在调试器下且未设置 NoDebugInherit 标志 - 新进程 B 也附加到相同的 DebugPort(相同的调试器)。

    NoDebugInherit 是如何设置的?

    如果我们通过CreateProcess api 启动进程 - 如果我们将DEBUG_ONLY_THIS_PROCESS 设置为NoDebugInherit 设置为true。如果我们使用DEBUG_PROCESS 没有 DEBUG_ONLY_THIS_PROCESS - NoDebugInherit 设置为 false - 结果新进程创建的所有子进程也将被调试。

    如果我们通过DebugActiveProcess 附加到已经运行的进程NoDebugInherit 设置为true。因此,如果此进程启动新进程 - 它将不会被调试。

    我们可以通过NtQueryInformationProcessNtSetInformationProcessProcessDebugFlags 查询和设置这个NoDebugInherit PROCESSINFOCLASS(它在ntddk.h 中声明) .有了这个我们可以随时通过下一个代码查询和更改ProcessDebugFlags

    // from WRK\WRK-v1.2\public\sdk\inc\ntpsapi.h  
    
    //
    // Define process debug flags
    //
    #define PROCESS_DEBUG_INHERIT 0x00000001
    
    NTSTATUS SetDebugInherit(HANDLE hProcess, BOOLEAN bInherit)
    {
        ULONG DebugFlags;
    
        // hProcess must have PROCESS_QUERY_INFORMATION access
        NTSTATUS status = NtQueryInformationProcess(hProcess, ProcessDebugFlags, &DebugFlags, sizeof(DebugFlags), 0);
    
        if (0 <= status)
        {
            bInherit ? DebugFlags |= PROCESS_DEBUG_INHERIT : DebugFlags &= ~PROCESS_DEBUG_INHERIT;
    
            // hProcess must have PROCESS_SET_INFORMATION access
            status = NtSetInformationProcess(hProcess, ProcessDebugFlags, &DebugFlags, sizeof(DebugFlags));
        }
    
        return status;
    }
    

    如果返回 MSVSWinDbg - 它总是以 DEBUG_ONLY_THIS_PROCESS 启动新进程。即使我们自己将NoDebugInherit 设置为false 并启动新进程——无论如何,如果我们使用MSVS,新进程将不会被调试甚至不会运行。如果 WinDbg 尝试一次正式的调试 2(和更多)进程,但也不能这样做。你需要更好的调试器,它可以同时调试多个进程。

    另一种可能性在进程 A 中设置断点 CreateProcessInternalW 并在它命中后 - 将断点设置为 NtResumeThread(这必须是临时断点 - 仅在 CreateProcessInternalW 命中之后) .当NtResumeThread 命中时 - 新进程B 已经启动(处于挂起状态)。此时您可以运行 MSVSWinDbg 的新实例并附加到它。但是这里也可能会出现问题,因为大多数调试器(MSVSWinDbg)使用DebugActiveProcess。这个 api 在调用 NtDebugActiveProcess 之后需要并且足以开始调试过程,由于某种原因在目标进程 (DbgUiRemoteBreakin) 中创建 (DbgUiIssueRemoteBreakin) 新线程。结果新进程开始在这个线程上执行。在 xp 中这会导致进程初始化失败。在现代 Windows 中 - 这通常是可行的,但无论如何都会影响进程执行 - 主进程线程不是第一个进程。

    如果 B 是你的进程 - 所以你可以修改它的代码,你总是可以在你想要附加/中断调试器的地方做下一步:

    while (!IsDebuggerPresent()) Sleep(1000);
    __debugbreak();
    

    或者如果你可以显示 gui:

    WCHAR sz[64];
    swprintf(sz, L"attact to %u(0x%x)\n", GetCurrentProcessId(), GetCurrentProcessId());
    while (!IsDebuggerPresent()) MessageBoxW(0,0,sz, MB_ICONINFORMATION);
    __debugbreak();
    

    【讨论】:

    • 非常感谢,我用messagebox的方式^_^
    【解决方案2】:

    当您手动附加到进程 B 时,它必须已经运行了一段时间。

    通过插件“Microsoft Child Process Debugging Power Tool”,VS 可以在子进程启动时自动附加到子进程,您可以在main() 的第一条语句处中断。

    【讨论】:

      猜你喜欢
      • 2014-04-23
      • 1970-01-01
      • 2015-12-13
      • 1970-01-01
      • 2010-12-01
      • 2020-12-04
      • 1970-01-01
      • 2017-08-03
      • 1970-01-01
      相关资源
      最近更新 更多