简体   繁体   English

使用C#远程发送命令到WinDbg

[英]Sending commands to WinDbg remotely using C#

In my application, WinDbg gets launched and I wondered if there was any way of sending certain commands through to WinDbg (for example sending the letter k (to show the callstack) from the C# application? 在我的应用程序中,WinDbg被启动,我想知道是否有任何方法可以将某些命令发送到WinDbg(例如,从C#应用程序发送字母k(以显示调用堆栈)?

I've read around some use of user32.dll which has functions that can help with this but I am unclear of how to proceed and include it in my app. 我已经阅读了一些user32.dll的用法,该函数具有可以帮助解决此问题的功能,但是我不清楚如何继续并将其包含在我的应用程序中。

Any help would be greatly appreciated. 任何帮助将不胜感激。

Steve 史蒂夫

If you want to fully control the debug engine, then you should just host it inside your C# application using the exposed COM interfaces. 如果要完全控制调试引擎,则应使用公开的COM接口将其托管在C#应用程序中。

You can find sample code for automating the debug engine in the WinDbg installation directory (eg C:\\Program Files (x86)\\Windows Kits\\8.1\\Debuggers\\x64\\sdk\\samples). 您可以在WinDbg安装目录中找到用于自动化调试引擎的示例代码(例如C:\\ Program Files(x86)\\ Windows Kits \\ 8.1 \\ Debuggers \\ x64 \\ sdk \\ samples)。 This blog post shows how to get a stack trace using the API (in C), so you don't have to parse the output after issuing a k command. 这篇博客文章展示了如何使用API​​(在C语言中)获取堆栈跟踪,因此您不必在发出k命令后解析输出。

The hardest part is just finding/creating all the IDebug* [ComImport] interfaces in C# for all the exposed objects. 最困难的部分是为所有公开的对象使用C#查找/创建所有IDebug * [ComImport]接口。 But once you have them, you would do something like this: 但是一旦有了它们,您将执行以下操作:

internal static class WinDbgBase
{
    // STDAPI DebugCreate(__in REFIID InterfaceId, __out PVOID* Interface);
    [DllImport("dbgeng.dll", EntryPoint = "DebugCreate", CallingConvention = CallingConvention.StdCall)]
    public static extern int DebugCreate([In] ref System.Guid InterfaceId, ref System.IntPtr Interface);
}

Guid uuidof_IDebugClient4 = new Guid("{ca83c3de-5089-4cf8-93c8-d892387f2a5e}");
IntPtr pObj = IntPtr.Zero;
int hr = WinDbgBase.DebugCreate(ref uuidof_IDebugClient4, ref pObj);
IDebugClient4 _client = (IDebugClient4)Marshal.GetTypedObjectForIUnknown(pObj, typeof(IDebugClient4));

// QueryInterface the other objects
IDebugControl4 _control = (IDebugControl4)_client;

_client.AttachProcess(0, ProcessId, DEBUG_ATTACH.DEBUG_ATTACH_DEFAULT);
_control.WaitForEvent(DEBUG_WAIT.DEBUG_WAIT_DEFAULT, Win32.INFINITE);
...

If you are dealing with managed targets, then it is even possible to load up the SOS extension, get the managed stack (as previously mentioned) and then merge it with the native stack trace so that you can show the full stack with all the native to/from managed transitions. 如果要处理托管目标,那么甚至可以加载SOS扩展,获取托管堆栈(如前所述),然后将其与本机堆栈跟踪合并,以便可以显示所有本机堆栈的完整堆栈往返于托管过渡。

References - Listing of all Debugger COM objects 参考- 所有Debugger COM对象的清单

No need to send keystrokes. 无需发送击键。 There's a more reliable way: see the WinDbg help for .ocommand . 有一种更可靠的方法:请参阅WinDbg帮助以获得.ocommand It works by sending commands through OutputDebugString , which is Debug.WriteLine() (Debug build) or Trace.WriteLine() (Release build) in .NET. 它通过.NET中的Debug.WriteLine()(Debug build)或Trace.WriteLine()(Release build)通过OutputDebugString发送命令来工作。

As you also start the debugger by yourself, you probably want to execute .ocommand immediately at startup which you can do by adding the -c command line switch: 当您还自己启动调试器时,您可能希望在启动时立即执行.ocommand ,您可以通过添加-c命令行开关来执行:

windbg.exe -p <PID> -c ".ocommand <Magic>;g"

This approach is a quick any dirty way. 这种方法是任何肮脏的快速方法。 @joshpoley`s answer is the cleaner way if you want a long term stable solution. 如果您想要长期稳定的解决方案,@ joshpoley的答案是更简洁的方法。

Note that for .NET the native callstack k might not be what you want. 请注意,对于.NET,本机调用堆栈k可能不是您想要的。 Try !clrstack or !dumpstack of the SOS extension (which you can load using .loadby sos clr or .loadby sos mscorwks depending on your .NET version). 尝试SOS扩展的!clrstack!dumpstack (您可以使用.loadby sos clr.loadby sos mscorwks具体取决于您的.NET版本)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM