mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1020 lines
32 KiB
1020 lines
32 KiB
// ReadLogsDlg.cpp : implementation file
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#include "emshell.h"
|
|
#include "ReadLogsDlg.h"
|
|
#include "EmShell.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
extern BSTR CopyBSTR( LPBYTE pb, ULONG cb );
|
|
|
|
const char* gslCarriageReturn = "\r";
|
|
const TCHAR* gtcFileOpenFlags = _T("w+b");
|
|
const TCHAR* gtcTempFilenameSeed = _T("ems");
|
|
const char* gslFirstChance = "first chance";
|
|
const char* gslCode = " - code";
|
|
const char* gslKV = "> kv";
|
|
const char* gslChildEBP = "ChildEBP";
|
|
const char* gslPrompt = ">";
|
|
const char* gslUEIP = "> u eip";
|
|
const char* gslSemiColon = ":";
|
|
const char* gslReadLogsAV = "READLOGS_AV";
|
|
const char* gslReadLogsDB = "READLOGS_DB";
|
|
const char* gslTildaStarKV = "~*kv";
|
|
const char* gslBangLocks = "!locks";
|
|
const char* gslIDColon = "id: ";
|
|
const char* gslCritSecText = "CritSec ";
|
|
const char gslSpace = ' ';
|
|
const char* gslOwningThread = "OwningThread";
|
|
const char* gslPeriod = ".";
|
|
const char* gslWaitForSingleObject = "WaitForSingleObject";
|
|
const char* gslWaitForMultipleObjects = "WaitForMultipleObjects";
|
|
const char* gslWaitForCriticalSection = "WaitForCriticalSection";
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CReadLogsDlg dialog
|
|
|
|
|
|
CReadLogsDlg::CReadLogsDlg(PEmObject pEmObj, IEmManager *pEmMgr, CWnd* pParent /*=NULL*/)
|
|
: CDialog(CReadLogsDlg::IDD, pParent)
|
|
{
|
|
_ASSERTE( pEmObj != NULL );
|
|
_ASSERTE( pEmMgr != NULL );
|
|
|
|
m_pEmObject = pEmObj;
|
|
m_pIEmManager = pEmMgr;
|
|
m_bAdvancedWindow = FALSE;
|
|
m_pLogFile = NULL;
|
|
|
|
//{{AFX_DATA_INIT(CReadLogsDlg)
|
|
m_csCompleteLog = _T("");
|
|
m_strExceptionType = _T("");
|
|
m_strExceptionLocation = _T("");
|
|
m_strFailingInstruction = _T("");
|
|
//}}AFX_DATA_INIT
|
|
}
|
|
|
|
|
|
void CReadLogsDlg::DoDataExchange(CDataExchange* pDX)
|
|
{
|
|
CDialog::DoDataExchange(pDX);
|
|
//{{AFX_DATA_MAP(CReadLogsDlg)
|
|
DDX_Control(pDX, IDC_STATIC_EXCEPINFO, m_ctlStaticExcepInfo);
|
|
DDX_Control(pDX, IDC_STATIC_HANGINFO, m_staticHangInfo);
|
|
DDX_Control(pDX, IDC_STATIC_FAILING_INSTRUCTION, m_ctlStaticFailingInstruction);
|
|
DDX_Control(pDX, IDC_STATIC_EXCEPTION_LOCATION, m_ctlStaticExceptionLocation);
|
|
DDX_Control(pDX, IDC_STATIC_EXCEPTION_TYPE, m_ctlStaticExceptionType);
|
|
DDX_Control(pDX, IDC_STATIC_CALL_STACK, m_ctlStaticCallStack);
|
|
DDX_Control(pDX, IDC_EDIT_FAILING_INSTRUCTION, m_ctlEditFailingInstruction);
|
|
DDX_Control(pDX, IDC_EDIT_EXCEPTION_TYPE, m_ctlEditExceptionType);
|
|
DDX_Control(pDX, IDC_EDIT_EXCEPTION_LOCATION, m_ctlEditExceptionLocation);
|
|
DDX_Control(pDX, IDC_LIST_CALL_STACK, m_ctlListControl);
|
|
DDX_Control(pDX, IDC_ADVANCED, m_ctrlAdvancedBtn);
|
|
DDX_Control(pDX, IDC_EDIT_READLOGS, m_ctrlCompleteReadLog);
|
|
DDX_Text(pDX, IDC_EDIT_READLOGS, m_csCompleteLog);
|
|
DDX_Text(pDX, IDC_EDIT_EXCEPTION_TYPE, m_strExceptionType);
|
|
DDX_Text(pDX, IDC_EDIT_EXCEPTION_LOCATION, m_strExceptionLocation);
|
|
DDX_Text(pDX, IDC_EDIT_FAILING_INSTRUCTION, m_strFailingInstruction);
|
|
//}}AFX_DATA_MAP
|
|
}
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(CReadLogsDlg, CDialog)
|
|
//{{AFX_MSG_MAP(CReadLogsDlg)
|
|
ON_BN_CLICKED(IDC_ADVANCED, OnAdvanced)
|
|
ON_WM_DESTROY()
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CReadLogsDlg message handlers
|
|
|
|
BOOL CReadLogsDlg::OnInitDialog()
|
|
{
|
|
CDialog::OnInitDialog();
|
|
|
|
// TODO: Add extra initialization here
|
|
|
|
HRESULT hr = E_FAIL;
|
|
ULONG lRead = 0L;
|
|
size_t tWritten = 0;
|
|
BSTR bstrEmObj = NULL;
|
|
TCHAR szTempDirPath[MAX_PATH] = {0};
|
|
TCHAR szTempFileName[MAX_PATH] = {0};
|
|
char lpszLogData[ISTREAM_BUFFER_SIZE];
|
|
|
|
do {
|
|
CWaitCursor wait;
|
|
|
|
if( !m_pEmObject || !m_pIEmManager ) break;
|
|
|
|
bstrEmObj = CopyBSTR( (LPBYTE) m_pEmObject, sizeof EmObject );
|
|
|
|
//Load the read logs stream from the manager
|
|
hr = m_pIEmManager->GetEmFileInterface( bstrEmObj, (IStream **)&m_pIEmStream );
|
|
if( FAILED(hr) ) break;
|
|
|
|
SysFreeString( bstrEmObj );
|
|
|
|
//Get the temporary system path
|
|
if ( 0 == GetTempPath( MAX_PATH, szTempDirPath ) ) break;
|
|
|
|
//Create a temp filename
|
|
GetTempFileName( szTempDirPath, gtcTempFilenameSeed, 0, szTempFileName);
|
|
|
|
m_pTempLogFileName = szTempFileName;
|
|
|
|
//Create a temp file in the system temp directory
|
|
m_pLogFile = _tfopen( m_pTempLogFileName, gtcFileOpenFlags );
|
|
if ( m_pLogFile == NULL ) break;
|
|
|
|
//Check the second line, if it's not either READLOGS_AV OR READLOGS_DB, cancel
|
|
for (int i = 1; i < 2; i++) {
|
|
|
|
hr = m_pIEmStream->Read( (void *)lpszLogData, ISTREAM_BUFFER_SIZE, &lRead );
|
|
if ( lRead == 0 || FAILED( hr ) ) break;
|
|
|
|
m_csCompleteLog += lpszLogData;
|
|
|
|
tWritten = fwrite( lpszLogData, sizeof( char ), lRead, m_pLogFile );
|
|
if ( tWritten == 0 ) {
|
|
hr = E_FAIL;
|
|
break;
|
|
}
|
|
|
|
if ( i == 1) {
|
|
|
|
//Check to see which version of the dlg we should be showing
|
|
if ( strstr( lpszLogData, gslReadLogsAV ) )
|
|
m_eReadLogType = ReadLogsType_Exception;
|
|
else if ( strstr( lpszLogData, gslReadLogsDB ) )
|
|
m_eReadLogType = ReadLogsType_Hang;
|
|
else
|
|
m_eReadLogType = ReadLogsType_None;
|
|
|
|
}
|
|
} while ( FALSE );
|
|
|
|
if ( FAILED( hr) ) break;
|
|
|
|
//Continue to read the log into the temp file
|
|
do {
|
|
|
|
hr = m_pIEmStream->Read( (void *)lpszLogData, ISTREAM_BUFFER_SIZE, &lRead );
|
|
if ( lRead == 0 || FAILED( hr ) ) break;
|
|
|
|
m_csCompleteLog += lpszLogData;
|
|
|
|
tWritten = fwrite( lpszLogData, sizeof( char ), lRead, m_pLogFile );
|
|
if ( tWritten == 0 ) {
|
|
hr = E_FAIL;
|
|
break;
|
|
}
|
|
|
|
} while (TRUE);
|
|
|
|
if ( FAILED( hr ) ) break;
|
|
|
|
//Flush the data to the file.
|
|
fflush( m_pLogFile );
|
|
|
|
switch ( m_eReadLogType ) {
|
|
case ReadLogsType_Exception:
|
|
ParseAndInitExceptionView();
|
|
break;
|
|
case ReadLogsType_Hang:
|
|
ParseAndInitHangView();
|
|
break;
|
|
case ReadLogsType_None:
|
|
ParseAndInitNoneView();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
UpdateData(FALSE);
|
|
} while ( FALSE );
|
|
|
|
SysFreeString( bstrEmObj );
|
|
|
|
if (m_pIEmStream) m_pIEmStream->Release();
|
|
|
|
//
|
|
// a-mando
|
|
//
|
|
ShowAppropriateControls();
|
|
ResizeAndReposControl();
|
|
// a-mando
|
|
|
|
SetDialogSize(FALSE);
|
|
|
|
if( FAILED(hr) ) {
|
|
//Show msg box
|
|
((CEmshellApp*)AfxGetApp())->DisplayErrMsgFromHR(hr);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE; // return TRUE unless you set the focus to a control
|
|
// EXCEPTION: OCX Property Pages should return FALSE
|
|
}
|
|
|
|
void CReadLogsDlg::SetDialogSize(BOOL bAdvanced)
|
|
{
|
|
CRect rtCompleteLog,
|
|
rtDlg;
|
|
|
|
GetWindowRect( &rtDlg );
|
|
m_ctrlCompleteReadLog.GetWindowRect( &rtCompleteLog );
|
|
|
|
rtDlg.bottom = rtCompleteLog.top;
|
|
|
|
if( bAdvanced ) {
|
|
|
|
rtDlg.bottom = rtCompleteLog.bottom + DLG_PIXEL_EXTEND_SIZE;
|
|
m_ctrlCompleteReadLog.ShowWindow(SW_SHOW);
|
|
}
|
|
|
|
MoveWindow(rtDlg);
|
|
}
|
|
|
|
void CReadLogsDlg::OnAdvanced()
|
|
{
|
|
CString csTemp;
|
|
|
|
// TODO: Add your control notification handler code here
|
|
|
|
if( !m_bAdvancedWindow )
|
|
{
|
|
SetDialogSize( TRUE );
|
|
m_bAdvancedWindow = TRUE;
|
|
|
|
csTemp.LoadString( IDS_READLOGS_ADVOPEN );
|
|
m_ctrlAdvancedBtn.SetWindowText( csTemp );
|
|
}
|
|
else
|
|
{
|
|
SetDialogSize(FALSE);
|
|
m_bAdvancedWindow = FALSE;
|
|
|
|
csTemp.LoadString( IDS_READLOGS_ADVCLOSE );
|
|
m_ctrlAdvancedBtn.SetWindowText( csTemp );
|
|
}
|
|
}
|
|
|
|
CReadLogsDlg::~CReadLogsDlg()
|
|
{
|
|
POSITION pos = NULL;
|
|
CString key;
|
|
CString* pVal = NULL;
|
|
|
|
ASSERT( m_pLogFile == NULL );
|
|
|
|
}
|
|
|
|
void CReadLogsDlg::ParseAndInitHangView()
|
|
{
|
|
//Show the controls for this view
|
|
//Hide the controls for this view
|
|
|
|
//Build map of critical sections
|
|
BuildCriticalSectionsMap();
|
|
|
|
//Build map of thread ID's
|
|
BuildThreadIDMap();
|
|
|
|
//Set the file cursor to the beginning of the logfile
|
|
ProcessKvThreadBlocks();
|
|
}
|
|
|
|
//
|
|
// a-mando
|
|
//
|
|
void CReadLogsDlg::ShowAppropriateControls()
|
|
{
|
|
//Enable the controls based on what view is selected
|
|
switch ( m_eReadLogType ) {
|
|
case ReadLogsType_None:
|
|
case ReadLogsType_Exception:
|
|
m_ctlStaticExcepInfo.ShowWindow(SW_SHOW);
|
|
m_staticHangInfo.ShowWindow(SW_HIDE);
|
|
m_ctlStaticFailingInstruction.ShowWindow(SW_SHOW);
|
|
m_ctlStaticExceptionLocation.ShowWindow(SW_SHOW);
|
|
m_ctlStaticExceptionType.ShowWindow(SW_SHOW);
|
|
m_ctlStaticCallStack.ShowWindow(SW_SHOW);
|
|
m_ctlEditFailingInstruction.ShowWindow(SW_SHOW);
|
|
m_ctlEditExceptionType.ShowWindow(SW_SHOW);
|
|
m_ctlEditExceptionLocation.ShowWindow(SW_SHOW);
|
|
m_ctlListControl.ShowWindow(SW_SHOW);
|
|
break;
|
|
case ReadLogsType_Hang:
|
|
m_staticHangInfo.ShowWindow(SW_SHOW);
|
|
//Disable all the controls except for the m_ctlHangListControl
|
|
break;
|
|
}
|
|
}
|
|
// a-mando
|
|
|
|
void CReadLogsDlg::ParseAndInitNoneView()
|
|
{
|
|
//Show the controls for this view
|
|
//Hide the controls for this view
|
|
|
|
}
|
|
|
|
void CReadLogsDlg::ParseAndInitExceptionView()
|
|
{
|
|
char szBuffer[MAX_TEMP_BUFFER_SIZE] = {0};
|
|
TCHAR szTmpBuffer[MAX_TEMP_BUFFER_SIZE] = {0};
|
|
char* pszOffset = NULL;
|
|
long lLastLineOffset = 0L;
|
|
char szException[MAX_TEMP_BUFFER_SIZE] = {0};
|
|
BOOL bFound = FALSE;
|
|
|
|
//Show the controls for this view
|
|
//Hide the controls for this view
|
|
|
|
do {
|
|
//Set the file cursor to the beginning of the logfile
|
|
fseek( m_pLogFile, 0, SEEK_SET );
|
|
|
|
do {
|
|
|
|
//Search through each line looking for the "(first chance)" text
|
|
pszOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
|
|
if ( pszOffset == NULL ) break;
|
|
|
|
pszOffset = strstr( szBuffer, gslFirstChance );
|
|
if ( pszOffset == 0 ) continue;
|
|
|
|
//Get the current byte offset. Note this is the next line, not the first chance line
|
|
lLastLineOffset = ftell( m_pLogFile );
|
|
if ( lLastLineOffset == -1L ) break;
|
|
|
|
//Store off the line just matched
|
|
strcpy( szException, szBuffer );
|
|
|
|
bFound = TRUE;
|
|
|
|
} while ( TRUE );
|
|
|
|
if ( !bFound ) break;
|
|
|
|
//Parse the szException for the readable exception text
|
|
//Get the position of the word "code", and then only get the string up to that point
|
|
pszOffset = strstr( szException, gslCode );
|
|
|
|
if ( pszOffset != NULL ) //a-kjaw, bug ID: 296028
|
|
*pszOffset = '\0';
|
|
|
|
//Store off szException to the dialog control
|
|
m_strExceptionType = szException;
|
|
|
|
bFound = FALSE; //Reset
|
|
|
|
//Handle ~KV
|
|
//Set the file pointer back to the last exception position or break if there is a problem
|
|
do {
|
|
if ( fseek( m_pLogFile, lLastLineOffset, SEEK_SET ) ) break;
|
|
|
|
do {
|
|
|
|
//Search through each line looking for the "> kv" text
|
|
pszOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
|
|
if ( pszOffset == NULL ) break;
|
|
|
|
pszOffset = strstr( szBuffer, gslKV );
|
|
if ( pszOffset == 0 ) continue;
|
|
|
|
bFound = TRUE;
|
|
|
|
break;
|
|
|
|
} while ( TRUE );
|
|
|
|
if ( !bFound ) break;
|
|
|
|
bFound = FALSE; //Reset
|
|
|
|
do {
|
|
|
|
//Search through each line looking for the "ChildEBP" text
|
|
pszOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
|
|
if ( pszOffset == NULL ) break;
|
|
|
|
pszOffset = strstr( szBuffer, gslChildEBP );
|
|
if ( pszOffset == 0 ) continue;
|
|
|
|
bFound = TRUE;
|
|
|
|
break;
|
|
|
|
} while ( TRUE );
|
|
|
|
if ( !bFound ) break;
|
|
|
|
bFound = FALSE; //Reset
|
|
|
|
do {
|
|
|
|
//Search through each line getting the call stack strings and
|
|
//populating the list control with them
|
|
pszOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
|
|
if ( pszOffset == NULL ) break;
|
|
|
|
pszOffset = strstr( szBuffer, gslPrompt );
|
|
if ( pszOffset != 0 ) break;
|
|
|
|
pszOffset = strstr( szBuffer, gslCarriageReturn );
|
|
*pszOffset = 0;
|
|
|
|
//Get the string from offset 45 on and insert into list control
|
|
mbstowcs( szTmpBuffer, szBuffer + sizeof( char[45] ), MAX_TEMP_BUFFER_SIZE );
|
|
|
|
m_ctlListControl.AddString( szTmpBuffer );
|
|
|
|
} while ( TRUE );
|
|
|
|
} while ( FALSE );
|
|
|
|
//Handle u eip
|
|
do {
|
|
|
|
if ( fseek( m_pLogFile, lLastLineOffset, SEEK_SET ) ) break;
|
|
|
|
do {
|
|
|
|
//Search through each line looking for the "> u eip" text
|
|
pszOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
|
|
if ( pszOffset == NULL ) break;
|
|
|
|
pszOffset = strstr( szBuffer, gslUEIP );
|
|
if ( pszOffset == 0 ) continue;
|
|
|
|
bFound = TRUE;
|
|
|
|
break;
|
|
|
|
} while ( TRUE );
|
|
|
|
if ( !bFound ) break;
|
|
|
|
bFound = FALSE; //Reset
|
|
|
|
//Get the first item in the list control
|
|
m_ctlListControl.GetText( 0, m_strExceptionLocation );
|
|
|
|
do {
|
|
|
|
//Get the immediate next line and stuff it into the failing instruction
|
|
pszOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
|
|
if ( pszOffset == NULL ) break;
|
|
|
|
//If the line has a semicolon, skip it.
|
|
pszOffset = strstr( szBuffer, gslSemiColon );
|
|
if ( pszOffset != NULL ) {
|
|
pszOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
|
|
}
|
|
|
|
pszOffset = strstr( szBuffer, gslCarriageReturn );
|
|
*pszOffset = 0;
|
|
|
|
m_strFailingInstruction = szBuffer + sizeof( char[26] );
|
|
|
|
bFound = TRUE;
|
|
|
|
break;
|
|
|
|
} while ( TRUE );
|
|
|
|
} while ( FALSE );
|
|
|
|
} while ( FALSE );
|
|
|
|
if ( !bFound ) {
|
|
|
|
//We didn't find an exception, error to the user
|
|
}
|
|
}
|
|
|
|
void CReadLogsDlg::OnDestroy()
|
|
{
|
|
CDialog::OnDestroy();
|
|
|
|
// TODO: Add your message handler code here
|
|
//Release the handle to the file
|
|
if ( m_pLogFile ) {
|
|
|
|
fclose( m_pLogFile );
|
|
m_pLogFile = NULL;
|
|
DeleteFile( m_pTempLogFileName );
|
|
}
|
|
}
|
|
|
|
|
|
void CReadLogsDlg::BuildCriticalSectionsMap()
|
|
{
|
|
BOOL bFound = FALSE;
|
|
char *pszOffset = NULL;
|
|
char *pszTempOffset = NULL;
|
|
char szBuffer[MAX_TEMP_BUFFER_SIZE] = {0};
|
|
CString csAddress;
|
|
CString *pcsOwningThread = NULL;
|
|
|
|
do {
|
|
//Set the file cursor to the beginning of the logfile
|
|
fseek( m_pLogFile, 0, SEEK_SET );
|
|
|
|
do {
|
|
|
|
//Search through each line looking for the "!Locks" command
|
|
pszOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
|
|
if ( pszOffset == NULL ) break;
|
|
|
|
pszOffset = strstr( szBuffer, gslBangLocks );
|
|
if ( pszOffset == NULL ) continue;
|
|
|
|
bFound = TRUE;
|
|
break;
|
|
} while ( TRUE );
|
|
|
|
if ( !bFound ) break;
|
|
bFound = FALSE;
|
|
|
|
//We're now at the !Locks area of the log file
|
|
do {
|
|
|
|
//We are now poised to extract the critical section address and the internal thread ID
|
|
do {
|
|
|
|
//Search through the block looking for the "CritSec" text or the "> " prompt
|
|
pszOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
|
|
if ( pszOffset == NULL ) break;
|
|
|
|
pszOffset = strstr( szBuffer, gslCritSecText );
|
|
|
|
//If "CritSec" is not in the string, look for the prompt
|
|
if ( pszOffset == NULL ) {
|
|
|
|
pszOffset = strstr( szBuffer, gslPrompt );
|
|
|
|
//If the prompt is not in the string, continue
|
|
if ( pszOffset == NULL ) {
|
|
continue;
|
|
}
|
|
else break;
|
|
}
|
|
|
|
pszOffset = strstr( szBuffer, gslCarriageReturn );
|
|
if( pszOffset != NULL ) // a-mando, bug ID: 296029
|
|
*pszOffset = '\0';
|
|
|
|
//We have a "CritSec", get the address from the right most edge
|
|
pszOffset = strrchr( szBuffer, gslSpace );
|
|
if ( pszOffset == NULL ) break;
|
|
|
|
csAddress = pszOffset + 1;
|
|
|
|
csAddress.MakeLower();
|
|
|
|
bFound = TRUE;
|
|
break;
|
|
} while ( TRUE );
|
|
|
|
if ( !bFound ) break;
|
|
bFound = FALSE;
|
|
|
|
do {
|
|
|
|
//Search through the block looking for the "OwningThread" text or the "> " prompt
|
|
pszOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
|
|
if ( pszOffset == NULL ) break;
|
|
|
|
pszOffset = strstr( szBuffer, gslOwningThread );
|
|
|
|
//If "OwningThread" is not in the string, look for the prompt
|
|
if ( pszOffset == NULL ) {
|
|
|
|
pszOffset = strstr( szBuffer, gslPrompt );
|
|
|
|
//If the prompt is not in the string, continue
|
|
if ( pszOffset == NULL ) {
|
|
continue;
|
|
}
|
|
else break;
|
|
}
|
|
|
|
//We have an "OwningThread", get the internal thread ID from the right most edge
|
|
pszOffset = strrchr( szBuffer, gslSpace );
|
|
if ( pszOffset == NULL ) break;
|
|
|
|
pszTempOffset = strstr( pszOffset, gslCarriageReturn );
|
|
if ( pszTempOffset != NULL ) *pszTempOffset = '\0';
|
|
|
|
CString pcsOwningThread = pszOffset + 1 ;
|
|
|
|
//Add the address and owning thread to the critical section map
|
|
m_mapCriticalSection.SetAt( csAddress, (CString&) pcsOwningThread );
|
|
|
|
bFound = TRUE;
|
|
break;
|
|
} while ( TRUE );
|
|
|
|
if ( !bFound ) break;
|
|
bFound = FALSE;
|
|
|
|
} while ( TRUE );
|
|
|
|
if ( !bFound ) break;
|
|
bFound = FALSE;
|
|
|
|
} while ( FALSE );
|
|
}
|
|
|
|
void CReadLogsDlg::BuildThreadIDMap()
|
|
{
|
|
BOOL bFound = FALSE;
|
|
char *pszStartOffset = NULL;
|
|
char *pszEndOffset = NULL;
|
|
char szBuffer[MAX_TEMP_BUFFER_SIZE] = {0};
|
|
CString* pcsThreadVal = NULL;
|
|
CString csThreadKey;
|
|
|
|
do {
|
|
//Set the file cursor to the beginning of the logfile
|
|
fseek( m_pLogFile, 0, SEEK_SET );
|
|
|
|
do {
|
|
|
|
//Search through each line looking for the "~*kv" command
|
|
pszStartOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
|
|
if ( pszStartOffset == NULL ) break;
|
|
|
|
pszStartOffset = strstr( szBuffer, gslTildaStarKV );
|
|
if ( pszStartOffset == NULL ) continue;
|
|
|
|
bFound = TRUE;
|
|
break;
|
|
} while ( TRUE );
|
|
|
|
if ( !bFound ) break;
|
|
bFound = FALSE;
|
|
|
|
//We're now at the ~*kv area of the log file
|
|
do {
|
|
|
|
//We are now poised to extract the critical section address and the internal thread ID
|
|
do {
|
|
|
|
//Search through the block looking for the "id: " text or the "> " prompt
|
|
pszStartOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
|
|
if ( pszStartOffset == NULL ) break;
|
|
|
|
pszStartOffset = strstr( szBuffer, gslIDColon );
|
|
|
|
//If "id: " is not in the string, look for the prompt
|
|
if ( pszStartOffset == NULL ) {
|
|
|
|
pszStartOffset = strstr( szBuffer, gslPrompt );
|
|
|
|
//If the prompt is not in the string, continue
|
|
if ( pszStartOffset == NULL ) {
|
|
continue;
|
|
}
|
|
else break;
|
|
}
|
|
|
|
//We have an "id: ", get the internal thread ID and ordered thread ID
|
|
CString pcsThreadVal = GetThreadID( szBuffer );
|
|
|
|
csThreadKey = GetThreadNumber( szBuffer );
|
|
|
|
csThreadKey.MakeLower();
|
|
|
|
m_mapThreadID.SetAt( csThreadKey, (CString&) pcsThreadVal );
|
|
|
|
bFound = TRUE;
|
|
break;
|
|
} while ( TRUE );
|
|
|
|
if ( !bFound ) break;
|
|
bFound = FALSE;
|
|
|
|
} while ( TRUE );
|
|
|
|
if ( !bFound ) break;
|
|
bFound = FALSE;
|
|
|
|
}while ( FALSE );
|
|
|
|
}
|
|
|
|
char* CReadLogsDlg::GetThreadID( char* szBuffer )
|
|
{
|
|
char *pszStartOffset = NULL;
|
|
char *pszEndOffset = NULL;
|
|
|
|
do {
|
|
pszStartOffset = strstr( szBuffer, gslPeriod );
|
|
if ( pszStartOffset == NULL ) break;
|
|
|
|
if ( pszStartOffset == szBuffer ) {
|
|
szBuffer++;
|
|
continue;
|
|
}
|
|
|
|
pszStartOffset++;
|
|
|
|
//increment 1 past the period we're sitting on. Unless it's the first one we're encountering
|
|
pszEndOffset = strchr( pszStartOffset, gslSpace );
|
|
if ( pszEndOffset == NULL ) break;
|
|
*pszEndOffset = '\0';
|
|
|
|
break;
|
|
} while ( TRUE );
|
|
|
|
return pszStartOffset;
|
|
}
|
|
|
|
char* CReadLogsDlg::GetThreadNumber( char* szBuffer )
|
|
{
|
|
char *pszStartOffset = NULL;
|
|
char *pszEndOffset = NULL;
|
|
|
|
//Look for the first occurance of a numeric number
|
|
pszStartOffset = szBuffer;
|
|
for ( ; (!isdigit( *pszStartOffset ) || *pszStartOffset == '.') && *pszStartOffset != '\0'; ) {
|
|
pszStartOffset++;
|
|
}
|
|
pszEndOffset = strchr( pszStartOffset, gslSpace );
|
|
*pszEndOffset = '\0';
|
|
|
|
return pszStartOffset;
|
|
}
|
|
|
|
void CReadLogsDlg::GetFirstParameter( char* szBuffer, CString &str )
|
|
{
|
|
char* token = NULL;
|
|
|
|
//Tokenize the buffer and get the 3rd token and set to str
|
|
token = strtok( szBuffer, &gslSpace );
|
|
|
|
for ( int i = 1; i < 3 && token != NULL; i++)
|
|
{
|
|
/* Get next token: */
|
|
token = strtok( NULL, &gslSpace );
|
|
}
|
|
|
|
str = token;
|
|
}
|
|
|
|
void CReadLogsDlg::GetSecondParameter( char* szBuffer, CString &str )
|
|
{
|
|
char* token = NULL;
|
|
|
|
//Tokenize the buffer and get the 3rd token and set to str
|
|
token = strtok( szBuffer, &gslSpace );
|
|
|
|
for ( int i = 1; i < 4 && token != NULL; i++)
|
|
{
|
|
/* Get next token: */
|
|
token = strtok( NULL, &gslSpace );
|
|
}
|
|
|
|
str = token;
|
|
}
|
|
|
|
void CReadLogsDlg::GetThirdParameter( char* szBuffer, CString &str )
|
|
{
|
|
char* token = NULL;
|
|
|
|
//Tokenize the buffer and get the 3rd token and set to str
|
|
token = strtok( szBuffer, &gslSpace );
|
|
|
|
for ( int i = 1; i < 5 && token != NULL; i++)
|
|
{
|
|
/* Get next token: */
|
|
token = strtok( NULL, &gslSpace );
|
|
}
|
|
|
|
str = token;
|
|
}
|
|
|
|
void CReadLogsDlg::ProcessKvThreadBlocks()
|
|
{
|
|
BOOL bFound = FALSE;
|
|
char *pszStartOffset = NULL;
|
|
char *pszEndOffset = NULL;
|
|
char szBuffer[MAX_TEMP_BUFFER_SIZE] = {0};
|
|
char szOriginalBuffer[MAX_TEMP_BUFFER_SIZE] = {0};
|
|
CString csThreadID;
|
|
CString csThreadNumber;
|
|
CString csOutput;
|
|
CString csFirstParameter;
|
|
CString csSecondParameter;
|
|
CString csThirdParameter;
|
|
CString csOwningThread;
|
|
|
|
do {
|
|
//Set the file cursor to the beginning of the logfile
|
|
fseek( m_pLogFile, 0, SEEK_SET );
|
|
|
|
do {
|
|
|
|
//Search through each line looking for the "~*kv" command
|
|
pszStartOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
|
|
if ( pszStartOffset == NULL ) break;
|
|
|
|
pszStartOffset = strstr( szBuffer, gslTildaStarKV );
|
|
if ( pszStartOffset == NULL ) continue;
|
|
|
|
bFound = TRUE;
|
|
break;
|
|
} while ( TRUE );
|
|
|
|
if ( !bFound ) break;
|
|
bFound = FALSE;
|
|
|
|
//We're now at the ~*kv area of the log file
|
|
do {
|
|
|
|
//We are now poised to handle determining output string for thread states
|
|
do {
|
|
|
|
//Search through the block looking for the "id: " text or the "> " prompt
|
|
pszStartOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
|
|
if ( pszStartOffset == NULL ) break;
|
|
|
|
//Let's keep a copy of the original around
|
|
strcpy( szOriginalBuffer, szBuffer );
|
|
|
|
pszStartOffset = strstr( szBuffer, gslIDColon );
|
|
|
|
//If "id: " is not in the string, look for the prompt
|
|
if ( pszStartOffset == NULL ) {
|
|
|
|
pszStartOffset = strstr( szBuffer, gslPrompt );
|
|
|
|
//If the prompt is not in the string, continue
|
|
if ( pszStartOffset == NULL ) {
|
|
continue;
|
|
}
|
|
else break;
|
|
}
|
|
|
|
csThreadNumber = GetThreadNumber( szBuffer );
|
|
strcpy( szBuffer, szOriginalBuffer );
|
|
|
|
csThreadID = GetThreadID( szBuffer );
|
|
strcpy( szBuffer, szOriginalBuffer );
|
|
|
|
//Search through the block looking for the "ChildEBP" text or the "> " prompt
|
|
pszStartOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
|
|
if ( pszStartOffset == NULL ) break;
|
|
|
|
//Let's keep a copy of the original around
|
|
strcpy( szOriginalBuffer, szBuffer );
|
|
|
|
pszStartOffset = strstr( szBuffer, gslChildEBP );
|
|
|
|
//If "ChildEBP" is not in the string, look for the prompt
|
|
if ( pszStartOffset == NULL ) {
|
|
|
|
pszStartOffset = strstr( szBuffer, gslPrompt );
|
|
|
|
//If the prompt is not in the string, continue
|
|
if ( pszStartOffset == NULL ) {
|
|
continue;
|
|
}
|
|
else break;
|
|
}
|
|
|
|
//We have found the "ChildEBP", so skip it! hahahahaa (what a waste)
|
|
pszStartOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
|
|
if ( pszStartOffset == NULL ) break;
|
|
|
|
//Let's keep a copy of the original around
|
|
strcpy( szOriginalBuffer, szBuffer );
|
|
|
|
if ( strstr( szBuffer, gslWaitForSingleObject ) ) {
|
|
//Get the next line and look for WaitForCriticalSection
|
|
pszStartOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
|
|
if ( pszStartOffset == NULL ) break;
|
|
|
|
//Let's keep a copy of the original around
|
|
strcpy( szOriginalBuffer, szBuffer );
|
|
|
|
pszStartOffset = strstr( szBuffer, gslWaitForCriticalSection );
|
|
|
|
//If "WaitForCriticalSection" is not in the string, look for the prompt
|
|
if ( pszStartOffset == NULL ) {
|
|
|
|
pszStartOffset = strstr( szBuffer, gslPrompt );
|
|
|
|
//If the prompt is not in the string, continue
|
|
if ( pszStartOffset == NULL ) {
|
|
GetFirstParameter( szBuffer, csFirstParameter );
|
|
strcpy( szBuffer, szOriginalBuffer );
|
|
csOutput.Format( _T("Thread %s is in a WaitForSingleObject() call on object %s"), csThreadNumber, csFirstParameter );
|
|
bFound = TRUE;
|
|
break;
|
|
}
|
|
else break;
|
|
}
|
|
|
|
//"WaitForCriticalSection" is in the string,
|
|
//Get the 5th token (3rd parameter) and look it up in the critical section map
|
|
GetThirdParameter( szBuffer, csThirdParameter );
|
|
strcpy( szBuffer, szOriginalBuffer );
|
|
csThirdParameter.MakeLower();
|
|
BOOL bFoundInMap = m_mapCriticalSection.Lookup( csThirdParameter, (CString&) csOwningThread );
|
|
|
|
//If not found in map,
|
|
if ( !bFoundInMap ) {
|
|
csOutput.Format( _T("Thread %s id: %s is in WaitForCriticalSection() call on object %s"), csThreadNumber, csThreadID, csThirdParameter );
|
|
bFound = TRUE;
|
|
break;
|
|
}
|
|
else {
|
|
csOutput.Format( _T("Thread %s id: %s is in WaitForCriticalSection() call on object %s. Thread %s is the owning thread."), csThreadNumber, csThreadID, csThirdParameter, csOwningThread);
|
|
bFound = TRUE;
|
|
break;
|
|
}
|
|
|
|
}
|
|
else if ( strstr( szBuffer, gslWaitForMultipleObjects ) ) {
|
|
GetFirstParameter( szBuffer, csFirstParameter );
|
|
strcpy( szBuffer, szOriginalBuffer );
|
|
GetSecondParameter( szBuffer, csSecondParameter );
|
|
strcpy( szBuffer, szOriginalBuffer );
|
|
|
|
csOutput.Format( _T("Thread %s id: %s is in a WaitForMultipleObjects() call on %s objects at address %s"), csThreadNumber, csThreadID, csFirstParameter, csSecondParameter );
|
|
bFound = TRUE;
|
|
break;
|
|
}
|
|
else {
|
|
csOutput.Format( _T("Thread %s is not in a known wait state"), csThreadNumber );
|
|
bFound = TRUE;
|
|
break;
|
|
}
|
|
|
|
if ( !bFound ) break;
|
|
bFound = FALSE;
|
|
|
|
} while ( TRUE );
|
|
|
|
if ( !bFound ) break;
|
|
bFound = FALSE;
|
|
|
|
//Output the text to the list control
|
|
m_ctlListControl.AddString( csOutput );
|
|
|
|
} while ( TRUE );
|
|
|
|
if ( !bFound ) break;
|
|
bFound = FALSE;
|
|
|
|
} while ( TRUE );
|
|
}
|
|
|
|
//
|
|
// a-mando
|
|
//
|
|
void CReadLogsDlg::ResizeAndReposControl()
|
|
{
|
|
CRect rtListCtrl,
|
|
rtHangInfo,
|
|
rtDlg;
|
|
|
|
GetWindowRect( &rtDlg );
|
|
m_staticHangInfo.GetWindowRect( &rtHangInfo );
|
|
m_ctlListControl.GetWindowRect( &rtListCtrl );
|
|
ScreenToClient( &rtDlg );
|
|
ScreenToClient( &rtHangInfo );
|
|
ScreenToClient( &rtListCtrl );
|
|
|
|
switch ( m_eReadLogType ) {
|
|
|
|
case ReadLogsType_Exception:
|
|
break;
|
|
|
|
case ReadLogsType_Hang:
|
|
m_staticHangInfo.ShowWindow(SW_SHOW);
|
|
rtListCtrl.left = rtDlg.left + DLG_PIXEL_EXTEND_SIZE;
|
|
rtListCtrl.top = rtHangInfo.bottom + DLG_PIXEL_EXTEND_SIZE;
|
|
m_ctlListControl.MoveWindow(&rtListCtrl);
|
|
m_ctlListControl.ShowWindow(SW_SHOW);
|
|
break;
|
|
|
|
case ReadLogsType_None:
|
|
//Disable all the controls
|
|
break;
|
|
}
|
|
|
|
}
|
|
// a-mando
|