
Роббинс Д. - Отладка приложений для Microsoft .NET и Microsoft Windows - 2004
.pdf

484 ЧАСТЬ IV Мощные средства и методы отладки неуправляемого кода
if ( EXCEPTION_STACK_OVERFLOW == pExPtrs >ExceptionRecord >ExceptionCode )
{
OutputDebugString(_T("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n")); OutputDebugString(_T("EXCEPTION_STACK_OVERFLOW occurred\n")); OutputDebugString(_T("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"));
}
if ( NULL != g_pfnCallBack )
{
//Сейчас нужно инициализировать символьную машину,
//чтобы подготовить ее к работе и иметь возможность
//получения базового адреса модуля по адресу ошибки. InitSymEng ( ) ;
//Проверка списка g_ahMod.
BOOL bCallIt = FALSE ; |
|
if ( 0 == g_uiModCount ) |
|
{ |
|
bCallIt = TRUE ; |
|
} |
|
else |
|
{ |
|
HINSTANCE hBaseAddr = (HINSTANCE) |
|
SymGetModuleBase64( GetCurrentProcess ( ) |
, |
(DWORD64)pExPtrs > |
|
ExceptionRecord > |
|
ExceptionAddress);
if ( NULL != hBaseAddr )
{
for ( UINT i = 0 ; i < g_uiModCount ; i ++ )
{
if ( hBaseAddr == g_ahMod[ i ] )
{
bCallIt = TRUE ; break ;
}
}
}
}
if ( TRUE == bCallIt )
{
//Прежде чем вызвать обработчик ошибок, я проверяю его
//наличие в памяти. Пользователь может забыть отменить
//регистрацию, и обработчик ошибок может быть
//некорректным, если он был выгружен. Однако, если
//по тому же адресу будет загружена какая нибудь другая
//функция, я ничего не смогу сделать.
ASSERT ( FALSE == IsBadCodePtr((FARPROC)g_pfnCallBack));


486 ЧАСТЬ IV Мощные средства и методы отладки неуправляемого кода
int iCurr = 0 ;
//Переменная для хранения временного значения. Это
//позволяет свести использование стека к минимуму. DWORD64 dwTemp ;
iCurr += BSUGetModuleBaseName ( GetCurrentProcess ( ) ,
NULL |
, |
g_szBuff |
, |
BUFF_SIZE |
) ; |
iCurr += wsprintf ( g_szBuff + iCurr , _T ( " caused an " ) ) ;
dwTemp = (DWORD_PTR) ConvertSimpleException(pExPtrs >ExceptionRecord >
ExceptionCode);
if ( NULL != dwTemp ) |
|
|
{ |
|
|
iCurr += wsprintf ( g_szBuff + iCurr , |
|
|
_T ( "%s" ) |
, |
|
dwTemp |
) ; |
|
} |
|
|
else |
|
|
{ |
|
|
iCurr += FormatMessage( FORMAT_MESSAGE_IGNORE_INSERTS | |
|
|
|
FORMAT_MESSAGE_FROM_HMODULE, |
|
GetModuleHandle (_T("NTDLL.DLL")) |
, |
|
pExPtrs >ExceptionRecord > |
|
|
|
ExceptionCode , |
|
0 |
|
, |
g_szBuff + iCurr |
, |
|
BUFF_SIZE |
, |
|
0 |
|
); |
} |
|
|
ASSERT ( iCurr < ( BUFF_SIZE MAX_PATH ) ) ; |
|
iCurr += wsprintf ( g_szBuff + iCurr , _T ( " in module " ) ) ;
dwTemp =
SymGetModuleBase64( GetCurrentProcess ( ) ,
(DWORD64)pExPtrs >ExceptionRecord >
ExceptionAddress ) ;
ASSERT ( NULL != dwTemp ) ;
if ( NULL == dwTemp )
{
iCurr += wsprintf ( g_szBuff + iCurr , _T ( "<UNKNOWN>" ) );
}
else

488 |
ЧАСТЬ IV Мощные средства и методы отладки неуправляемого кода |
||
|
|
||
|
|
||
|
|
||
|
BSUAnsi2Wide ( pSym >Name , pWideName , iLen + 1 ) ; |
||
|
lstrcpyn ( g_szBuff + iCurr |
, |
|
|
pWideName |
, |
|
|
BUFF_SIZE iCurr 1 |
) ; |
|
#else |
|
|
|
|
lstrcpyn ( g_szBuff + iCurr |
, |
|
|
pSym >Name |
, |
|
|
BUFF_SIZE iCurr 1 |
) ; |
|
#endif |
// UNICODE |
|
|
|
// Выход |
|
|
|
szRet = g_szBuff ; |
|
|
|
__leave ; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
if ( dwDisp > 0 ) |
|
|
|
{ |
|
|
|
iCurr += wsprintf ( g_szBuff + iCurr |
, |
|
|
k_NAMEDISPFMT |
, |
|
|
pSym >Name |
, |
|
|
dwDisp |
|
) ; |
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
iCurr += wsprintf ( g_szBuff + iCurr , |
||
|
k_NAMEFMT |
|
, |
|
pSym >Name |
) ; |
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
//Если символ не был найден, информация об исходном файле
//и номере строки также не будет получена, поэтому выходим. szRet = g_szBuff ;
__leave ;
}
ASSERT ( iCurr < ( BUFF_SIZE 200 ) ) ; |
|
// Поиск информации об исходном фале и номере строки. |
|
ZeroMemory ( &g_stLine , sizeof ( IMAGEHLP_LINE64 ) ) ; |
|
g_stLine.SizeOfStruct = sizeof ( IMAGEHLP_LINE64 ) ; |
|
DWORD dwLineDisp ; |
|
if ( TRUE == |
|
SymGetLineFromAddr64 ( GetCurrentProcess ( ) |
, |
(DWORD64)pExPtrs > |
|
ExceptionRecord > |
|


490 ЧАСТЬ IV Мощные средства и методы отладки неуправляемого кода
szRet = g_szBuff ;
}
__except ( EXCEPTION_EXECUTE_HANDLER )
{
ASSERT ( !"Crashed in GetFaultReason" ) ; szRet = NULL ;
}
return ( szRet ) ;
}
//Вспомогательная функция, позволяющая изолировать заполнение
//структуры кадра стека, которое зависит от процессора.
void FillInStackFrame ( PCONTEXT pCtx )
{
// Инициализация структуры STACKFRAME.
ZeroMemory ( &g_stFrame , sizeof ( STACKFRAME64 ) ) ;
#ifdef _X86_ |
|
|
|
|
g_stFrame.AddrPC.Offset |
= pCtx >Eip |
; |
|
|
g_stFrame.AddrPC.Mode |
= AddrModeFlat |
; |
|
|
g_stFrame.AddrStack.Offset |
= pCtx >Esp |
; |
|
|
g_stFrame.AddrStack.Mode |
= AddrModeFlat |
; |
|
|
g_stFrame.AddrFrame.Offset |
= pCtx >Ebp |
; |
|
|
g_stFrame.AddrFrame.Mode |
= AddrModeFlat ; |
|
||
#elif |
_AMD64_ |
|
|
|
g_stFrame.AddrPC.Offset |
= pCtx >Rip |
; |
|
|
g_stFrame.AddrPC.Mode |
= AddrModeFlat |
; |
|
|
g_stFrame.AddrStack.Offset |
= pCtx >Rsp |
; |
|
|
g_stFrame.AddrStack.Mode |
= AddrModeFlat |
; |
|
|
g_stFrame.AddrFrame.Offset |
= pCtx >Rbp |
; |
|
|
g_stFrame.AddrFrame.Mode |
= AddrModeFlat ; |
|
||
#elif |
_IA64_ |
|
|
|
#pragma message ( "IA64 NOT DEFINED!!" ) |
|
|
||
#pragma FORCE COMPILATION ABORT! |
|
|
||
#else |
|
|
|
|
#pragma message ( "CPU NOT DEFINED!!" ) |
|
|
||
#pragma FORCE COMPILATION ABORT! |
|
|
||
#endif |
|
|
|
|
} |
|
|
|
|
LPCTSTR BUGSUTIL_DLLINTERFACE __stdcall |
|
|
||
|
GetFirstStackTraceString ( DWORD |
dwOpts |
, |
|
|
|
EXCEPTION_POINTERS * pExPtrs |
) |
|
{ |
|
|
|
|
ASSERT ( FALSE == IsBadReadPtr ( pExPtrs |
, |
|
||
|
|
sizeof ( EXCEPTION_POINTERS * ))) ; |
||
if ( TRUE == IsBadReadPtr ( pExPtrs |
, |
|
||
|
|
sizeof ( EXCEPTION_POINTERS * ) ) ) |
|
|
{ |
|
|
|
|
TRACE0 ( "GetFirstStackTraceString invalid pExPtrs!\n" ) ;


492 |
ЧАСТЬ IV Мощные средства и методы отладки неуправляемого кода |
|||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Примечание: |
При использовании функций получения информации |
|
|
|
// |
об исходном |
файле и номере строки StackWalk |
|
|
// |
может вызвать нарушение доступа. |
|
|
|
BOOL bSWRet = StackWalk64 ( |
CH_MACHINE |
, |
|
|
|
|
GetCurrentProcess ( ) |
, |
|
|
|
GetCurrentThread ( ) |
, |
|
|
|
&g_stFrame |
, |
|
|
|
&g_stContext |
, |
|
|
|
CH_ReadProcessMemory |
, |
|
|
|
SymFunctionTableAccess64 |
, |
|
|
|
SymGetModuleBase64 |
, |
|
|
|
NULL |
); |
|
if ( ( FALSE == bSWRet ) || |
( 0 == g_stFrame.AddrFrame.Offset )) |
||
|
{ |
|
|
|
szRet = NULL ; __leave ;
}
//Прежде чем я начну все вычислять, мне нужно удостовериться
//в том, что адрес, возвращенный из StackWalk, действительно
//существует. Мне известны случаи, когда StackWalk возвращала
//TRUE, но адрес не относился к модулю данного процесса.
dwModBase = SymGetModuleBase64 ( GetCurrentProcess ( ) |
, |
||
g_stFrame.AddrPC.Offset |
) ; |
||
if ( 0 == dwModBase ) |
|
|
|
{ |
|
|
|
szRet = NULL ; |
|
|
|
__leave ; |
|
|
|
} |
|
|
|
int iCurr = 0 ; |
|
|
|
// Как минимум помещаем в буфер адрес. |
|
|
|
#ifdef _WIN64 |
|
|
|
iCurr += wsprintf ( g_szBuff + iCurr |
, |
|
|
_T ( "0x%016X" ) |
, |
|
|
g_stFrame.AddrPC.Offset |
) ; |
|
|
#else |
|
|
|
iCurr += wsprintf ( g_szBuff + iCurr |
, |
|
|
_T ( "%04X:%08X" ) |
, |
|
|
g_stContext.SegCs |
, |
|
|
g_stFrame.AddrPC.Offset |
) ; |
|
|
#endif |
|
|
|
// Выводить параметры? |
|
|
|
if ( GSTSO_PARAMS == ( dwOpts & GSTSO_PARAMS ) ) |
|
|
|
{ |
|
|
|
iCurr += wsprintf ( g_szBuff + iCurr |
|
, |
|
k_PARAMFMTSTRING |
|
, |
|
g_stFrame.Params[ 0 ] |
, |
|