我正在扩展中实现DebugExtensionProvideValue
,因此我可以提供自定义伪寄存器。它在CDB中工作得很好,最初在WinDbg中工作正常,但是在停止调试并打开一个新的可执行文件之后会发生一些事情,并且WinDbg会以一种奇怪的不可用状态结束。
当您触发问题时,WinDbg会将此消息打印到命令窗口:
无法发送回调,3131
在此之后,WinDbg似乎在命令窗口中两次打印所有输出!
我的扩展程序代码非常简单:
EXTERN_C HRESULT CALLBACK DebugExtensionProvideValue(PDEBUG_CLIENT Client, ULONG Flags, IN PCWSTR Name, OUT PULONG64 Value, OUT PULONG64 TypeModBase, OUT PULONG TypeId, OUT PULONG TypeFlags)
{
HRESULT hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
if (!Name || !Value || !TypeFlags)
{
hr = E_INVALIDARG;
}
else if (0 == lstrcmpiW(Name, L"$$test"))
{
*Value = 0xDeadCafeBabeBeefULL;
*TypeFlags = DEBUG_EXT_PVTYPE_IS_VALUE;
if (TypeId) *TypeId = 0; // Where are these types defined?
if (TypeModBase) *TypeModBase = 0;
hr = S_OK;
}
#if 0 // <-- ** Setting this to != 0 fixes the problem **
Client->Release(); // This does not feel right but it does seem to be required!
#endif
return hr;
}
EXTERN_C HRESULT CALLBACK DebugExtensionQueryValueNames(PDEBUG_CLIENT Client, ULONG Flags, OUT PWSTR Buffer, ULONG BufferChars, OUT PULONG BufferNeeded)
{
static const WCHAR pseregs[] = L"$$test\0";
if (BufferNeeded) *BufferNeeded = ARRAYSIZE(pseregs);
memcpy(Buffer, pseregs, min(sizeof(pseregs), BufferChars*sizeof(*Buffer)));
return ARRAYSIZE(pseregs) > BufferChars ? S_FALSE : S_OK;
}
EXTERN_C HRESULT CALLBACK DebugExtensionInitialize(OUT PULONG Version, OUT PULONG Flags)
{
*Version = DEBUG_EXTENSION_VERSION(1, 0), *Flags = 0;
return S_OK;
}
重现问题看起来像这样:
0:000> $$ Press Ctrl+E to open a executable, I'm going to open WinVer.exe
0:000> .load c:\test\myext.dll
0:000> ?@$$test
Evaluate expression: -2401039830915039505 = deadcafe`babebeef
0:000> $$ Press Shift+F5 to stop debugging
0:000> $$ Press Ctrl+E and open a executable again, WinDbg will now print "Unable to deliver callback, 3131"
我能够提出一个似乎有效的解决方法,但它感觉不对,因为我必须发布一个我从不QI的接口,也不是AddRef'ed。在我的最小测试数量中,这个黑客似乎永远不会崩溃,并且通过偷看IDebugClients引用计数它在多次调用时似乎是正确的。
据我所知,你无法停止调试并在CDB中打开这样的新.exe,所以看起来问题只能发生在WinDbg上。
我做错了什么或DbgEng中有错误?
答案 0 :(得分:0)
@Anders
我找到了一些时间在不同的代码路径中检查它,看起来dbgeng ClientListCapture / Find / fill / list / FindExt中有一个错误 递增的引用计数似乎没有减少,导致ref累积在每个关闭和打开时累加几个回调
我使用的代码路径是设置Extension Class
的m_ProvidedValue成员注意我还添加了代码来解决下面的其他两个查询TypeId和TypeModBase
#include <engextcpp.cpp>
ExtProvidedValue pval[];
class EXT_CLASS : public ExtExtension {
public:
void
handler (
_In_ ULONG Flags, _In_ PCWSTR ValueName, _Out_ PULONG64 Value,
_Out_ PULONG64 TypeModBase, _Out_ PULONG TypeId, _Out_ PULONG TypeFlags
) {
DEBUG_CACHED_SYMBOL_INFO Info;
ZeroMemory(&Info, sizeof(Info));
PCSTR Type = "ntdll!_LDR_DATA_TABLE_ENTRY";
HRESULT Status = E_FAIL;
if((Status = m_Symbols->GetSymbolTypeId(Type,&Info.Id,&Info.ModBase)) != S_OK) {
ThrowStatus(Status, "Unable to get type ID of '%s'", Type);
}
if (0 == lstrcmpiW(ValueName, L"$$test")) {
if(Value) { *Value = 0xDeadCafeBabeBeefULL; }
if(TypeModBase) { *TypeModBase = Info.ModBase; }
if(TypeId) { *TypeId = Info.Id; }
if(TypeFlags) { *TypeFlags = DEBUG_EXT_PVTYPE_IS_POINTER; }
}
};
HRESULT Initialize(void) {
this->m_ProvidedValues = pval;
return S_OK;
}
};
EXT_DECLARE_GLOBALS();
ExtProvideValueMethod mymethod = (ExtProvideValueMethod)&Extension::handler;
ExtProvidedValue pval[] = {L"$$test\0",mymethod,NULL,NULL};
def文件包含
EXPORTS
DebugExtensionInitialize
DebugExtensionQueryValueNames
DebugExtensionProvideValue
help
编译并与企业wdk链接如下
@echo off
IF "%donesetup%" == "" ( pushd .. )
IF "%donesetup%" == "" ( cd /d E:\ewdk )
IF "%donesetup%" == "" ( @call launchbuildenv.cmd )
IF "%donesetup%" == "" ( popd )
IF "%donesetup%" == "" ( set "donesetup=donesetup" )
IF "%INCLUDE%" == "" ( set "INCLUDE=%vcinstalldir%include;%windowssdkdir%Include\10.0.10586.0\ucrt;%windowssdkdir%Include\10.0.10586.0\um;%windowssdkdir%Include\10.0.10586.0\shared;%windowssdkdir%Debuggers\inc;" )
IF "%LIB%" == "" ( set "LIB=%vcinstalldir%\LIB;%WINDOWSSDKDIR%Lib\10.0.10586.0\ucrt\x86;%WINDOWSSDKDIR%Lib\10.0.10586.0\um\x86;%windowssdkdir%Debuggers\lib\x86")
IF "%LINKLIBS%" == "" ( set "LINKLIBS=user32.lib kernel32.lib dbgeng.lib dbghelp.lib" )
cl /LD /nologo /W3 /Zi /EHsc pstest.cpp /link /DEF:pstest.def /RELEASE %linklibs%
move /y pstest.dll "e:\ewdk\Program Files\Windows Kits\10\Debuggers\x86\winext"\.
将扩展加载到windbg和调用结果
Microsoft (R) Windows Debugger Version 10.0.10586.567 X86
0:000> .load pstest
0:000> ? @$$test (masm Evaluate)
Evaluate expression: -2401039830915039505 = deadcafe`babebeef
0:000> ?? @$$test (c++ Evaluate note the use of TypeId and TypeModbase
results in a type Display instead of a Int64 value)
struct _LDR_DATA_TABLE_ENTRY * 0xbabebeef
+0x000 InLoadOrderLinks : _LIST_ENTRY
+0x008 InMemoryOrderLinks : _LIST_ENTRY
+0x010 InInitializationOrderLinks : _LIST_ENTRY
+0x018 DllBase : ????
+0x01c EntryPoint : ????
+0x020 SizeOfImage : ??
+0x024 FullDllName : _UNICODE_STRING
+0x02c BaseDllName : _UNICODE_STRING
+0x034 Flags : ??
+0x038 LoadCount : ??
+0x03a TlsIndex : ??
+0x03c HashLinks : _LIST_ENTRY
+0x03c SectionPointer : ????
+0x040 CheckSum : ??
+0x044 TimeDateStamp : ??
+0x044 LoadedImports : ????
+0x048 EntryPointActivationContext : ????
+0x04c PatchInformation : ????
+0x050 ForwarderLinks : _LIST_ENTRY
+0x058 ServiceTagLinks : _LIST_ENTRY
+0x060 StaticLinks : _LIST_ENTRY
+0x068 ContextInformation : ????
+0x06c OriginalBase : ??
+0x070 LoadTime : _LARGE_INTEGER
并且如果我发布了Shift + f5和ctrl + e windbg抱怨它无法发送回调
如果重复shift + f5 / ctrl + e / load / invoke的过程
投诉的数量不断增加到windbg挂起的程度
尝试在挂起的callstack中处理ProcessPendingMessages