I'm implementing DebugExtensionProvideValue in my extension so I can provide custom pseudo-registers. It works perfectly in CDB and it works fine initially in WinDbg but after stopping debugging and opening a new executable something happens and WinDbg ends up in a weird unusable state.
WinDbg prints this message to the command window when you trigger the problem:
Unable to deliver callback, 3131
and after this happens WinDbg seems to print all output twice in the command window!
My extension code is very simple:
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;
}
Reproducing the issue looks something like this:
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"
I was able to come up with a workaround that does seem to work but it just does not feel right because I have to Release a interface I never QI'ed nor AddRef'ed. In my minimal amount of testing this hack never seemed to crash and by peeking at IDebugClients refcount it does seem correct over multiple calls.
As far as I can tell you cannot stop debugging and open a new .exe like this in CDB so it seems the problem can only happen WinDbg.
Am I doing something wrong or is there a bug in DbgEng?
@Anders
I found some time to check it in a different code-path and it appears there is a bug in dbgeng ClientListCapture / Find / fill / list / FindExt
an incremented Reference count doesnt seem to be decremented resulting in a ref accumulation adding up several callbacks on each close and open
the code-path i used was to set the m_ProvidedValue member of the Extension Class
Note I also added code to address your other two queries TypeId and TypeModBase below
def file contains
compiled and linked with enterprise wdk as follows
loading the extension into windbg and result of invocation
and as posted by you if i do Shift+f5 and ctrl+e windbg complains that it cannot deliver the callback
if the procedure of shift +f5 / ctrl+e / load / invoke is repeated
the number of complaints keeps on adding to the point that windbg hangs
trying to ProcessPendingMessages in hung callstack