Introduction
Is The Debugger Attached? As a very big part of my work is being a bugslayer,
I tend to have a need for more debugging or debug support code in my projects.
This article's code of substance is just one small function with effectively
about 13 lines of code. Seems rather insignificant, but it has been very useful
to me as a person who does a lot of debugging, and of course, that I even came
to writing this function was interesting in itself.
Details
The function is called IsDebuggerAttached()
. As the name implies, it returns
a BOOL
indication if a debugger is attached to the process. This was developed
on and for Windows NT 4.0, and also works on Windows 2000. I do not know if it
will work on Win9x as internal Windows structures differ. I will now go into
some example reason(s) I had the need for this, and how it might help others who
might have such needs as well.
One of the first things I consider one of the pillars of good programming
practices is the validation and verification of parameters coming into a
function. More importantly, the validation of pointers. I've had a steady supply
of 'business' due to the encounters of the lack of such practices in my last few
years of software engineering. There are situations where parameters coming into
a function should always be valid. In such a situation, the standard things to
do is to check the parameters for validity via ASSERT
's. This is perfect for
parameters that should never fail the assertion. The great thing about the
assertions is that it gives you the option to break into the debugger. In the
case of release builds, this is not available as the ASSERT
's evaluate to
nothing.
There were situations that I decided that I wanted to take different actions
depending on whether a debugger was attached to my process or not. If there was
no debugger attached, I had my code either popup a message box on a seriously
bad condition, or to output a debug string, and quietly continue on it's way if
it's possible. However, I also wanted it to be able to break at the spot of the
erroneous condition if a debugger was attached. And obviously, I didn't want to
build one version of the code that popped up a message box and/or output a debug
string, and another version that did a DebugBreak()
. Also, if you called a
DebugBreak()
and a debugger is not attached to you process, the system would
popup a nasty dialog indicating a debug break exception.
All that being said, this was clearly what I wanted :
if (Big_Bad_Error)
{
if (Debugger_Is_Attached)
{
Break_Into_Debugger;
}
else
{
Say_Something;
}
}
Here is the code for the function IsDebuggerAttached()
:
BOOL IsDebuggerAttached()
{
DWORD dw;
__asm
{
push eax
push ecx
mov eax, fs:[0x18]
mov eax, dword ptr [eax + 0x30]
mov ecx, dword ptr [eax]
mov dw, ecx
pop ecx
pop eax
}
return (BOOL)(dw & 0x00010000 ? TRUE : FALSE);
}
This is a dig into the Thread Information Block (TIB) of the process to
check if a debugger is attached. And for those who don't already know,
the FS register points to the current thread's TIB. Needless to say, coming
to this involved a fair amount of disassemblies of Windows while in the
debugger. Following, is code from the sample application for
this article. It's an MFC dialog app where the test is
done in the OnOK()
handler :
void CDebuggerDlg::OnOK()
{
LPBYTE lpBuffer = (LPBYTE)0x80000000;
ReadMemory(lpBuffer, 1024);
}
BOOL CDebuggerDlg::ReadMemory(LPVOID lpBuffer,
DWORD dwSize)
{
if (IsBadWritePtr(lpBuffer, dwSize))
{
if (IsDebuggerAttached())
{
__asm int 3
}
else
{
MessageBox(
"CDebuggerDlg::ReadMemory() : "
"Bad output buffer : lpBuffer!");
}
return FALSE;
}
return TRUE;
}
Well folks, I hope that this technique may be of use to some of you out there.