Интересная деталь отладочного API Win32: когда появляется событие OUTPUT_DEBUG_STRING_EVENT, то ответственным за получение строки для вывода является основной отладчик. Информация, переданная отладчику, включает расположение и длину строки. Получив это сообщение, отладчик читает память вне подчиненного отладчика. В главе 3 упоминалось, что при выполнении под отладчиком операторы трассировки могут легко изменить поведение приложения. Поскольку все потоки в приложении останавливаются, когда цикл отладки обрабатывает событие, вызов функции OutputDebugString в подчиненном отладчике означает, что все потоки стоят. Листинг 4-3 показывает, как WDBG обрабатывает событие OUTPUT_DEBUG_STRING_EVENT. Заметьте, что функция DBG_ReadProcessMemory является функцией-оболочкой вокруг ReadProcessMemory из LOCALASSIST.DLL.
Листинг 4-3.OutputDebugStringEvent изPROCESSDEBUGEVENTS.CPP
static
DWORD OutputDebugStringEvent ( CDebugBaseUser * pUserClass ,
LPDEBUGGEEINFO pData ,
DWORD dwProcessId,
DWORD dwThreadld ,
OUTPUT_DEBUG_STRING_INFO & stODSI )
{
TCHAR szBuff[ 512 ];
HANDLE hProc = pData->GetProcessHandle (); DWORD dwRead;
// Читать память.
BOOL bRet = DBG_ReadProcessMemory( hProc ,
stODSI.lpDebugStringData ,
szBuff, min ( sizeof ( szBuff) ,
stODSI.nDebugStringLength),
&dwRead ) ;
ASSERT ( TRUE == bRet);
if ( TRUE == bRet)
{
// Строку всегда завершает NULL .
szBuff [ dwRead + 1 ] = _T ( '\0');
// Преобразовать символы CR/LF .
pUserClass->ConvertCRLF ( szBuff, sizeof ( szBuff));
// Послать ковертированную строку в класс пользователя.
pUserClass->OutputDebugStringEvent ( dwProcessId,
dwThreadld , szBuff );
}
return ( DBG_CONTINUE);
}