Source code of Windows XP (NT5)
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

  1. // ReadLogsDlg.cpp : implementation file
  2. //
  3. #include "stdafx.h"
  4. #include "emshell.h"
  5. #include "ReadLogsDlg.h"
  6. #include "EmShell.h"
  7. #ifdef _DEBUG
  8. #define new DEBUG_NEW
  9. #undef THIS_FILE
  10. static char THIS_FILE[] = __FILE__;
  11. #endif
  12. extern BSTR CopyBSTR( LPBYTE pb, ULONG cb );
  13. const char* gslCarriageReturn = "\r";
  14. const TCHAR* gtcFileOpenFlags = _T("w+b");
  15. const TCHAR* gtcTempFilenameSeed = _T("ems");
  16. const char* gslFirstChance = "first chance";
  17. const char* gslCode = " - code";
  18. const char* gslKV = "> kv";
  19. const char* gslChildEBP = "ChildEBP";
  20. const char* gslPrompt = ">";
  21. const char* gslUEIP = "> u eip";
  22. const char* gslSemiColon = ":";
  23. const char* gslReadLogsAV = "READLOGS_AV";
  24. const char* gslReadLogsDB = "READLOGS_DB";
  25. const char* gslTildaStarKV = "~*kv";
  26. const char* gslBangLocks = "!locks";
  27. const char* gslIDColon = "id: ";
  28. const char* gslCritSecText = "CritSec ";
  29. const char gslSpace = ' ';
  30. const char* gslOwningThread = "OwningThread";
  31. const char* gslPeriod = ".";
  32. const char* gslWaitForSingleObject = "WaitForSingleObject";
  33. const char* gslWaitForMultipleObjects = "WaitForMultipleObjects";
  34. const char* gslWaitForCriticalSection = "WaitForCriticalSection";
  35. /////////////////////////////////////////////////////////////////////////////
  36. // CReadLogsDlg dialog
  37. CReadLogsDlg::CReadLogsDlg(PEmObject pEmObj, IEmManager *pEmMgr, CWnd* pParent /*=NULL*/)
  38. : CDialog(CReadLogsDlg::IDD, pParent)
  39. {
  40. _ASSERTE( pEmObj != NULL );
  41. _ASSERTE( pEmMgr != NULL );
  42. m_pEmObject = pEmObj;
  43. m_pIEmManager = pEmMgr;
  44. m_bAdvancedWindow = FALSE;
  45. m_pLogFile = NULL;
  46. //{{AFX_DATA_INIT(CReadLogsDlg)
  47. m_csCompleteLog = _T("");
  48. m_strExceptionType = _T("");
  49. m_strExceptionLocation = _T("");
  50. m_strFailingInstruction = _T("");
  51. //}}AFX_DATA_INIT
  52. }
  53. void CReadLogsDlg::DoDataExchange(CDataExchange* pDX)
  54. {
  55. CDialog::DoDataExchange(pDX);
  56. //{{AFX_DATA_MAP(CReadLogsDlg)
  57. DDX_Control(pDX, IDC_STATIC_EXCEPINFO, m_ctlStaticExcepInfo);
  58. DDX_Control(pDX, IDC_STATIC_HANGINFO, m_staticHangInfo);
  59. DDX_Control(pDX, IDC_STATIC_FAILING_INSTRUCTION, m_ctlStaticFailingInstruction);
  60. DDX_Control(pDX, IDC_STATIC_EXCEPTION_LOCATION, m_ctlStaticExceptionLocation);
  61. DDX_Control(pDX, IDC_STATIC_EXCEPTION_TYPE, m_ctlStaticExceptionType);
  62. DDX_Control(pDX, IDC_STATIC_CALL_STACK, m_ctlStaticCallStack);
  63. DDX_Control(pDX, IDC_EDIT_FAILING_INSTRUCTION, m_ctlEditFailingInstruction);
  64. DDX_Control(pDX, IDC_EDIT_EXCEPTION_TYPE, m_ctlEditExceptionType);
  65. DDX_Control(pDX, IDC_EDIT_EXCEPTION_LOCATION, m_ctlEditExceptionLocation);
  66. DDX_Control(pDX, IDC_LIST_CALL_STACK, m_ctlListControl);
  67. DDX_Control(pDX, IDC_ADVANCED, m_ctrlAdvancedBtn);
  68. DDX_Control(pDX, IDC_EDIT_READLOGS, m_ctrlCompleteReadLog);
  69. DDX_Text(pDX, IDC_EDIT_READLOGS, m_csCompleteLog);
  70. DDX_Text(pDX, IDC_EDIT_EXCEPTION_TYPE, m_strExceptionType);
  71. DDX_Text(pDX, IDC_EDIT_EXCEPTION_LOCATION, m_strExceptionLocation);
  72. DDX_Text(pDX, IDC_EDIT_FAILING_INSTRUCTION, m_strFailingInstruction);
  73. //}}AFX_DATA_MAP
  74. }
  75. BEGIN_MESSAGE_MAP(CReadLogsDlg, CDialog)
  76. //{{AFX_MSG_MAP(CReadLogsDlg)
  77. ON_BN_CLICKED(IDC_ADVANCED, OnAdvanced)
  78. ON_WM_DESTROY()
  79. //}}AFX_MSG_MAP
  80. END_MESSAGE_MAP()
  81. /////////////////////////////////////////////////////////////////////////////
  82. // CReadLogsDlg message handlers
  83. BOOL CReadLogsDlg::OnInitDialog()
  84. {
  85. CDialog::OnInitDialog();
  86. // TODO: Add extra initialization here
  87. HRESULT hr = E_FAIL;
  88. ULONG lRead = 0L;
  89. size_t tWritten = 0;
  90. BSTR bstrEmObj = NULL;
  91. TCHAR szTempDirPath[MAX_PATH] = {0};
  92. TCHAR szTempFileName[MAX_PATH] = {0};
  93. char lpszLogData[ISTREAM_BUFFER_SIZE];
  94. do {
  95. CWaitCursor wait;
  96. if( !m_pEmObject || !m_pIEmManager ) break;
  97. bstrEmObj = CopyBSTR( (LPBYTE) m_pEmObject, sizeof EmObject );
  98. //Load the read logs stream from the manager
  99. hr = m_pIEmManager->GetEmFileInterface( bstrEmObj, (IStream **)&m_pIEmStream );
  100. if( FAILED(hr) ) break;
  101. SysFreeString( bstrEmObj );
  102. //Get the temporary system path
  103. if ( 0 == GetTempPath( MAX_PATH, szTempDirPath ) ) break;
  104. //Create a temp filename
  105. GetTempFileName( szTempDirPath, gtcTempFilenameSeed, 0, szTempFileName);
  106. m_pTempLogFileName = szTempFileName;
  107. //Create a temp file in the system temp directory
  108. m_pLogFile = _tfopen( m_pTempLogFileName, gtcFileOpenFlags );
  109. if ( m_pLogFile == NULL ) break;
  110. //Check the second line, if it's not either READLOGS_AV OR READLOGS_DB, cancel
  111. for (int i = 1; i < 2; i++) {
  112. hr = m_pIEmStream->Read( (void *)lpszLogData, ISTREAM_BUFFER_SIZE, &lRead );
  113. if ( lRead == 0 || FAILED( hr ) ) break;
  114. m_csCompleteLog += lpszLogData;
  115. tWritten = fwrite( lpszLogData, sizeof( char ), lRead, m_pLogFile );
  116. if ( tWritten == 0 ) {
  117. hr = E_FAIL;
  118. break;
  119. }
  120. if ( i == 1) {
  121. //Check to see which version of the dlg we should be showing
  122. if ( strstr( lpszLogData, gslReadLogsAV ) )
  123. m_eReadLogType = ReadLogsType_Exception;
  124. else if ( strstr( lpszLogData, gslReadLogsDB ) )
  125. m_eReadLogType = ReadLogsType_Hang;
  126. else
  127. m_eReadLogType = ReadLogsType_None;
  128. }
  129. } while ( FALSE );
  130. if ( FAILED( hr) ) break;
  131. //Continue to read the log into the temp file
  132. do {
  133. hr = m_pIEmStream->Read( (void *)lpszLogData, ISTREAM_BUFFER_SIZE, &lRead );
  134. if ( lRead == 0 || FAILED( hr ) ) break;
  135. m_csCompleteLog += lpszLogData;
  136. tWritten = fwrite( lpszLogData, sizeof( char ), lRead, m_pLogFile );
  137. if ( tWritten == 0 ) {
  138. hr = E_FAIL;
  139. break;
  140. }
  141. } while (TRUE);
  142. if ( FAILED( hr ) ) break;
  143. //Flush the data to the file.
  144. fflush( m_pLogFile );
  145. switch ( m_eReadLogType ) {
  146. case ReadLogsType_Exception:
  147. ParseAndInitExceptionView();
  148. break;
  149. case ReadLogsType_Hang:
  150. ParseAndInitHangView();
  151. break;
  152. case ReadLogsType_None:
  153. ParseAndInitNoneView();
  154. break;
  155. default:
  156. break;
  157. }
  158. UpdateData(FALSE);
  159. } while ( FALSE );
  160. SysFreeString( bstrEmObj );
  161. if (m_pIEmStream) m_pIEmStream->Release();
  162. //
  163. // a-mando
  164. //
  165. ShowAppropriateControls();
  166. ResizeAndReposControl();
  167. // a-mando
  168. SetDialogSize(FALSE);
  169. if( FAILED(hr) ) {
  170. //Show msg box
  171. ((CEmshellApp*)AfxGetApp())->DisplayErrMsgFromHR(hr);
  172. return FALSE;
  173. }
  174. return TRUE; // return TRUE unless you set the focus to a control
  175. // EXCEPTION: OCX Property Pages should return FALSE
  176. }
  177. void CReadLogsDlg::SetDialogSize(BOOL bAdvanced)
  178. {
  179. CRect rtCompleteLog,
  180. rtDlg;
  181. GetWindowRect( &rtDlg );
  182. m_ctrlCompleteReadLog.GetWindowRect( &rtCompleteLog );
  183. rtDlg.bottom = rtCompleteLog.top;
  184. if( bAdvanced ) {
  185. rtDlg.bottom = rtCompleteLog.bottom + DLG_PIXEL_EXTEND_SIZE;
  186. m_ctrlCompleteReadLog.ShowWindow(SW_SHOW);
  187. }
  188. MoveWindow(rtDlg);
  189. }
  190. void CReadLogsDlg::OnAdvanced()
  191. {
  192. CString csTemp;
  193. // TODO: Add your control notification handler code here
  194. if( !m_bAdvancedWindow )
  195. {
  196. SetDialogSize( TRUE );
  197. m_bAdvancedWindow = TRUE;
  198. csTemp.LoadString( IDS_READLOGS_ADVOPEN );
  199. m_ctrlAdvancedBtn.SetWindowText( csTemp );
  200. }
  201. else
  202. {
  203. SetDialogSize(FALSE);
  204. m_bAdvancedWindow = FALSE;
  205. csTemp.LoadString( IDS_READLOGS_ADVCLOSE );
  206. m_ctrlAdvancedBtn.SetWindowText( csTemp );
  207. }
  208. }
  209. CReadLogsDlg::~CReadLogsDlg()
  210. {
  211. POSITION pos = NULL;
  212. CString key;
  213. CString* pVal = NULL;
  214. ASSERT( m_pLogFile == NULL );
  215. }
  216. void CReadLogsDlg::ParseAndInitHangView()
  217. {
  218. //Show the controls for this view
  219. //Hide the controls for this view
  220. //Build map of critical sections
  221. BuildCriticalSectionsMap();
  222. //Build map of thread ID's
  223. BuildThreadIDMap();
  224. //Set the file cursor to the beginning of the logfile
  225. ProcessKvThreadBlocks();
  226. }
  227. //
  228. // a-mando
  229. //
  230. void CReadLogsDlg::ShowAppropriateControls()
  231. {
  232. //Enable the controls based on what view is selected
  233. switch ( m_eReadLogType ) {
  234. case ReadLogsType_None:
  235. case ReadLogsType_Exception:
  236. m_ctlStaticExcepInfo.ShowWindow(SW_SHOW);
  237. m_staticHangInfo.ShowWindow(SW_HIDE);
  238. m_ctlStaticFailingInstruction.ShowWindow(SW_SHOW);
  239. m_ctlStaticExceptionLocation.ShowWindow(SW_SHOW);
  240. m_ctlStaticExceptionType.ShowWindow(SW_SHOW);
  241. m_ctlStaticCallStack.ShowWindow(SW_SHOW);
  242. m_ctlEditFailingInstruction.ShowWindow(SW_SHOW);
  243. m_ctlEditExceptionType.ShowWindow(SW_SHOW);
  244. m_ctlEditExceptionLocation.ShowWindow(SW_SHOW);
  245. m_ctlListControl.ShowWindow(SW_SHOW);
  246. break;
  247. case ReadLogsType_Hang:
  248. m_staticHangInfo.ShowWindow(SW_SHOW);
  249. //Disable all the controls except for the m_ctlHangListControl
  250. break;
  251. }
  252. }
  253. // a-mando
  254. void CReadLogsDlg::ParseAndInitNoneView()
  255. {
  256. //Show the controls for this view
  257. //Hide the controls for this view
  258. }
  259. void CReadLogsDlg::ParseAndInitExceptionView()
  260. {
  261. char szBuffer[MAX_TEMP_BUFFER_SIZE] = {0};
  262. TCHAR szTmpBuffer[MAX_TEMP_BUFFER_SIZE] = {0};
  263. char* pszOffset = NULL;
  264. long lLastLineOffset = 0L;
  265. char szException[MAX_TEMP_BUFFER_SIZE] = {0};
  266. BOOL bFound = FALSE;
  267. //Show the controls for this view
  268. //Hide the controls for this view
  269. do {
  270. //Set the file cursor to the beginning of the logfile
  271. fseek( m_pLogFile, 0, SEEK_SET );
  272. do {
  273. //Search through each line looking for the "(first chance)" text
  274. pszOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
  275. if ( pszOffset == NULL ) break;
  276. pszOffset = strstr( szBuffer, gslFirstChance );
  277. if ( pszOffset == 0 ) continue;
  278. //Get the current byte offset. Note this is the next line, not the first chance line
  279. lLastLineOffset = ftell( m_pLogFile );
  280. if ( lLastLineOffset == -1L ) break;
  281. //Store off the line just matched
  282. strcpy( szException, szBuffer );
  283. bFound = TRUE;
  284. } while ( TRUE );
  285. if ( !bFound ) break;
  286. //Parse the szException for the readable exception text
  287. //Get the position of the word "code", and then only get the string up to that point
  288. pszOffset = strstr( szException, gslCode );
  289. if ( pszOffset != NULL ) //a-kjaw, bug ID: 296028
  290. *pszOffset = '\0';
  291. //Store off szException to the dialog control
  292. m_strExceptionType = szException;
  293. bFound = FALSE; //Reset
  294. //Handle ~KV
  295. //Set the file pointer back to the last exception position or break if there is a problem
  296. do {
  297. if ( fseek( m_pLogFile, lLastLineOffset, SEEK_SET ) ) break;
  298. do {
  299. //Search through each line looking for the "> kv" text
  300. pszOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
  301. if ( pszOffset == NULL ) break;
  302. pszOffset = strstr( szBuffer, gslKV );
  303. if ( pszOffset == 0 ) continue;
  304. bFound = TRUE;
  305. break;
  306. } while ( TRUE );
  307. if ( !bFound ) break;
  308. bFound = FALSE; //Reset
  309. do {
  310. //Search through each line looking for the "ChildEBP" text
  311. pszOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
  312. if ( pszOffset == NULL ) break;
  313. pszOffset = strstr( szBuffer, gslChildEBP );
  314. if ( pszOffset == 0 ) continue;
  315. bFound = TRUE;
  316. break;
  317. } while ( TRUE );
  318. if ( !bFound ) break;
  319. bFound = FALSE; //Reset
  320. do {
  321. //Search through each line getting the call stack strings and
  322. //populating the list control with them
  323. pszOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
  324. if ( pszOffset == NULL ) break;
  325. pszOffset = strstr( szBuffer, gslPrompt );
  326. if ( pszOffset != 0 ) break;
  327. pszOffset = strstr( szBuffer, gslCarriageReturn );
  328. *pszOffset = 0;
  329. //Get the string from offset 45 on and insert into list control
  330. mbstowcs( szTmpBuffer, szBuffer + sizeof( char[45] ), MAX_TEMP_BUFFER_SIZE );
  331. m_ctlListControl.AddString( szTmpBuffer );
  332. } while ( TRUE );
  333. } while ( FALSE );
  334. //Handle u eip
  335. do {
  336. if ( fseek( m_pLogFile, lLastLineOffset, SEEK_SET ) ) break;
  337. do {
  338. //Search through each line looking for the "> u eip" text
  339. pszOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
  340. if ( pszOffset == NULL ) break;
  341. pszOffset = strstr( szBuffer, gslUEIP );
  342. if ( pszOffset == 0 ) continue;
  343. bFound = TRUE;
  344. break;
  345. } while ( TRUE );
  346. if ( !bFound ) break;
  347. bFound = FALSE; //Reset
  348. //Get the first item in the list control
  349. m_ctlListControl.GetText( 0, m_strExceptionLocation );
  350. do {
  351. //Get the immediate next line and stuff it into the failing instruction
  352. pszOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
  353. if ( pszOffset == NULL ) break;
  354. //If the line has a semicolon, skip it.
  355. pszOffset = strstr( szBuffer, gslSemiColon );
  356. if ( pszOffset != NULL ) {
  357. pszOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
  358. }
  359. pszOffset = strstr( szBuffer, gslCarriageReturn );
  360. *pszOffset = 0;
  361. m_strFailingInstruction = szBuffer + sizeof( char[26] );
  362. bFound = TRUE;
  363. break;
  364. } while ( TRUE );
  365. } while ( FALSE );
  366. } while ( FALSE );
  367. if ( !bFound ) {
  368. //We didn't find an exception, error to the user
  369. }
  370. }
  371. void CReadLogsDlg::OnDestroy()
  372. {
  373. CDialog::OnDestroy();
  374. // TODO: Add your message handler code here
  375. //Release the handle to the file
  376. if ( m_pLogFile ) {
  377. fclose( m_pLogFile );
  378. m_pLogFile = NULL;
  379. DeleteFile( m_pTempLogFileName );
  380. }
  381. }
  382. void CReadLogsDlg::BuildCriticalSectionsMap()
  383. {
  384. BOOL bFound = FALSE;
  385. char *pszOffset = NULL;
  386. char *pszTempOffset = NULL;
  387. char szBuffer[MAX_TEMP_BUFFER_SIZE] = {0};
  388. CString csAddress;
  389. CString *pcsOwningThread = NULL;
  390. do {
  391. //Set the file cursor to the beginning of the logfile
  392. fseek( m_pLogFile, 0, SEEK_SET );
  393. do {
  394. //Search through each line looking for the "!Locks" command
  395. pszOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
  396. if ( pszOffset == NULL ) break;
  397. pszOffset = strstr( szBuffer, gslBangLocks );
  398. if ( pszOffset == NULL ) continue;
  399. bFound = TRUE;
  400. break;
  401. } while ( TRUE );
  402. if ( !bFound ) break;
  403. bFound = FALSE;
  404. //We're now at the !Locks area of the log file
  405. do {
  406. //We are now poised to extract the critical section address and the internal thread ID
  407. do {
  408. //Search through the block looking for the "CritSec" text or the "> " prompt
  409. pszOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
  410. if ( pszOffset == NULL ) break;
  411. pszOffset = strstr( szBuffer, gslCritSecText );
  412. //If "CritSec" is not in the string, look for the prompt
  413. if ( pszOffset == NULL ) {
  414. pszOffset = strstr( szBuffer, gslPrompt );
  415. //If the prompt is not in the string, continue
  416. if ( pszOffset == NULL ) {
  417. continue;
  418. }
  419. else break;
  420. }
  421. pszOffset = strstr( szBuffer, gslCarriageReturn );
  422. if( pszOffset != NULL ) // a-mando, bug ID: 296029
  423. *pszOffset = '\0';
  424. //We have a "CritSec", get the address from the right most edge
  425. pszOffset = strrchr( szBuffer, gslSpace );
  426. if ( pszOffset == NULL ) break;
  427. csAddress = pszOffset + 1;
  428. csAddress.MakeLower();
  429. bFound = TRUE;
  430. break;
  431. } while ( TRUE );
  432. if ( !bFound ) break;
  433. bFound = FALSE;
  434. do {
  435. //Search through the block looking for the "OwningThread" text or the "> " prompt
  436. pszOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
  437. if ( pszOffset == NULL ) break;
  438. pszOffset = strstr( szBuffer, gslOwningThread );
  439. //If "OwningThread" is not in the string, look for the prompt
  440. if ( pszOffset == NULL ) {
  441. pszOffset = strstr( szBuffer, gslPrompt );
  442. //If the prompt is not in the string, continue
  443. if ( pszOffset == NULL ) {
  444. continue;
  445. }
  446. else break;
  447. }
  448. //We have an "OwningThread", get the internal thread ID from the right most edge
  449. pszOffset = strrchr( szBuffer, gslSpace );
  450. if ( pszOffset == NULL ) break;
  451. pszTempOffset = strstr( pszOffset, gslCarriageReturn );
  452. if ( pszTempOffset != NULL ) *pszTempOffset = '\0';
  453. CString pcsOwningThread = pszOffset + 1 ;
  454. //Add the address and owning thread to the critical section map
  455. m_mapCriticalSection.SetAt( csAddress, (CString&) pcsOwningThread );
  456. bFound = TRUE;
  457. break;
  458. } while ( TRUE );
  459. if ( !bFound ) break;
  460. bFound = FALSE;
  461. } while ( TRUE );
  462. if ( !bFound ) break;
  463. bFound = FALSE;
  464. } while ( FALSE );
  465. }
  466. void CReadLogsDlg::BuildThreadIDMap()
  467. {
  468. BOOL bFound = FALSE;
  469. char *pszStartOffset = NULL;
  470. char *pszEndOffset = NULL;
  471. char szBuffer[MAX_TEMP_BUFFER_SIZE] = {0};
  472. CString* pcsThreadVal = NULL;
  473. CString csThreadKey;
  474. do {
  475. //Set the file cursor to the beginning of the logfile
  476. fseek( m_pLogFile, 0, SEEK_SET );
  477. do {
  478. //Search through each line looking for the "~*kv" command
  479. pszStartOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
  480. if ( pszStartOffset == NULL ) break;
  481. pszStartOffset = strstr( szBuffer, gslTildaStarKV );
  482. if ( pszStartOffset == NULL ) continue;
  483. bFound = TRUE;
  484. break;
  485. } while ( TRUE );
  486. if ( !bFound ) break;
  487. bFound = FALSE;
  488. //We're now at the ~*kv area of the log file
  489. do {
  490. //We are now poised to extract the critical section address and the internal thread ID
  491. do {
  492. //Search through the block looking for the "id: " text or the "> " prompt
  493. pszStartOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
  494. if ( pszStartOffset == NULL ) break;
  495. pszStartOffset = strstr( szBuffer, gslIDColon );
  496. //If "id: " is not in the string, look for the prompt
  497. if ( pszStartOffset == NULL ) {
  498. pszStartOffset = strstr( szBuffer, gslPrompt );
  499. //If the prompt is not in the string, continue
  500. if ( pszStartOffset == NULL ) {
  501. continue;
  502. }
  503. else break;
  504. }
  505. //We have an "id: ", get the internal thread ID and ordered thread ID
  506. CString pcsThreadVal = GetThreadID( szBuffer );
  507. csThreadKey = GetThreadNumber( szBuffer );
  508. csThreadKey.MakeLower();
  509. m_mapThreadID.SetAt( csThreadKey, (CString&) pcsThreadVal );
  510. bFound = TRUE;
  511. break;
  512. } while ( TRUE );
  513. if ( !bFound ) break;
  514. bFound = FALSE;
  515. } while ( TRUE );
  516. if ( !bFound ) break;
  517. bFound = FALSE;
  518. }while ( FALSE );
  519. }
  520. char* CReadLogsDlg::GetThreadID( char* szBuffer )
  521. {
  522. char *pszStartOffset = NULL;
  523. char *pszEndOffset = NULL;
  524. do {
  525. pszStartOffset = strstr( szBuffer, gslPeriod );
  526. if ( pszStartOffset == NULL ) break;
  527. if ( pszStartOffset == szBuffer ) {
  528. szBuffer++;
  529. continue;
  530. }
  531. pszStartOffset++;
  532. //increment 1 past the period we're sitting on. Unless it's the first one we're encountering
  533. pszEndOffset = strchr( pszStartOffset, gslSpace );
  534. if ( pszEndOffset == NULL ) break;
  535. *pszEndOffset = '\0';
  536. break;
  537. } while ( TRUE );
  538. return pszStartOffset;
  539. }
  540. char* CReadLogsDlg::GetThreadNumber( char* szBuffer )
  541. {
  542. char *pszStartOffset = NULL;
  543. char *pszEndOffset = NULL;
  544. //Look for the first occurance of a numeric number
  545. pszStartOffset = szBuffer;
  546. for ( ; (!isdigit( *pszStartOffset ) || *pszStartOffset == '.') && *pszStartOffset != '\0'; ) {
  547. pszStartOffset++;
  548. }
  549. pszEndOffset = strchr( pszStartOffset, gslSpace );
  550. *pszEndOffset = '\0';
  551. return pszStartOffset;
  552. }
  553. void CReadLogsDlg::GetFirstParameter( char* szBuffer, CString &str )
  554. {
  555. char* token = NULL;
  556. //Tokenize the buffer and get the 3rd token and set to str
  557. token = strtok( szBuffer, &gslSpace );
  558. for ( int i = 1; i < 3 && token != NULL; i++)
  559. {
  560. /* Get next token: */
  561. token = strtok( NULL, &gslSpace );
  562. }
  563. str = token;
  564. }
  565. void CReadLogsDlg::GetSecondParameter( char* szBuffer, CString &str )
  566. {
  567. char* token = NULL;
  568. //Tokenize the buffer and get the 3rd token and set to str
  569. token = strtok( szBuffer, &gslSpace );
  570. for ( int i = 1; i < 4 && token != NULL; i++)
  571. {
  572. /* Get next token: */
  573. token = strtok( NULL, &gslSpace );
  574. }
  575. str = token;
  576. }
  577. void CReadLogsDlg::GetThirdParameter( char* szBuffer, CString &str )
  578. {
  579. char* token = NULL;
  580. //Tokenize the buffer and get the 3rd token and set to str
  581. token = strtok( szBuffer, &gslSpace );
  582. for ( int i = 1; i < 5 && token != NULL; i++)
  583. {
  584. /* Get next token: */
  585. token = strtok( NULL, &gslSpace );
  586. }
  587. str = token;
  588. }
  589. void CReadLogsDlg::ProcessKvThreadBlocks()
  590. {
  591. BOOL bFound = FALSE;
  592. char *pszStartOffset = NULL;
  593. char *pszEndOffset = NULL;
  594. char szBuffer[MAX_TEMP_BUFFER_SIZE] = {0};
  595. char szOriginalBuffer[MAX_TEMP_BUFFER_SIZE] = {0};
  596. CString csThreadID;
  597. CString csThreadNumber;
  598. CString csOutput;
  599. CString csFirstParameter;
  600. CString csSecondParameter;
  601. CString csThirdParameter;
  602. CString csOwningThread;
  603. do {
  604. //Set the file cursor to the beginning of the logfile
  605. fseek( m_pLogFile, 0, SEEK_SET );
  606. do {
  607. //Search through each line looking for the "~*kv" command
  608. pszStartOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
  609. if ( pszStartOffset == NULL ) break;
  610. pszStartOffset = strstr( szBuffer, gslTildaStarKV );
  611. if ( pszStartOffset == NULL ) continue;
  612. bFound = TRUE;
  613. break;
  614. } while ( TRUE );
  615. if ( !bFound ) break;
  616. bFound = FALSE;
  617. //We're now at the ~*kv area of the log file
  618. do {
  619. //We are now poised to handle determining output string for thread states
  620. do {
  621. //Search through the block looking for the "id: " text or the "> " prompt
  622. pszStartOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
  623. if ( pszStartOffset == NULL ) break;
  624. //Let's keep a copy of the original around
  625. strcpy( szOriginalBuffer, szBuffer );
  626. pszStartOffset = strstr( szBuffer, gslIDColon );
  627. //If "id: " is not in the string, look for the prompt
  628. if ( pszStartOffset == NULL ) {
  629. pszStartOffset = strstr( szBuffer, gslPrompt );
  630. //If the prompt is not in the string, continue
  631. if ( pszStartOffset == NULL ) {
  632. continue;
  633. }
  634. else break;
  635. }
  636. csThreadNumber = GetThreadNumber( szBuffer );
  637. strcpy( szBuffer, szOriginalBuffer );
  638. csThreadID = GetThreadID( szBuffer );
  639. strcpy( szBuffer, szOriginalBuffer );
  640. //Search through the block looking for the "ChildEBP" text or the "> " prompt
  641. pszStartOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
  642. if ( pszStartOffset == NULL ) break;
  643. //Let's keep a copy of the original around
  644. strcpy( szOriginalBuffer, szBuffer );
  645. pszStartOffset = strstr( szBuffer, gslChildEBP );
  646. //If "ChildEBP" is not in the string, look for the prompt
  647. if ( pszStartOffset == NULL ) {
  648. pszStartOffset = strstr( szBuffer, gslPrompt );
  649. //If the prompt is not in the string, continue
  650. if ( pszStartOffset == NULL ) {
  651. continue;
  652. }
  653. else break;
  654. }
  655. //We have found the "ChildEBP", so skip it! hahahahaa (what a waste)
  656. pszStartOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
  657. if ( pszStartOffset == NULL ) break;
  658. //Let's keep a copy of the original around
  659. strcpy( szOriginalBuffer, szBuffer );
  660. if ( strstr( szBuffer, gslWaitForSingleObject ) ) {
  661. //Get the next line and look for WaitForCriticalSection
  662. pszStartOffset = fgets( szBuffer, MAX_TEMP_BUFFER_SIZE, m_pLogFile );
  663. if ( pszStartOffset == NULL ) break;
  664. //Let's keep a copy of the original around
  665. strcpy( szOriginalBuffer, szBuffer );
  666. pszStartOffset = strstr( szBuffer, gslWaitForCriticalSection );
  667. //If "WaitForCriticalSection" is not in the string, look for the prompt
  668. if ( pszStartOffset == NULL ) {
  669. pszStartOffset = strstr( szBuffer, gslPrompt );
  670. //If the prompt is not in the string, continue
  671. if ( pszStartOffset == NULL ) {
  672. GetFirstParameter( szBuffer, csFirstParameter );
  673. strcpy( szBuffer, szOriginalBuffer );
  674. csOutput.Format( _T("Thread %s is in a WaitForSingleObject() call on object %s"), csThreadNumber, csFirstParameter );
  675. bFound = TRUE;
  676. break;
  677. }
  678. else break;
  679. }
  680. //"WaitForCriticalSection" is in the string,
  681. //Get the 5th token (3rd parameter) and look it up in the critical section map
  682. GetThirdParameter( szBuffer, csThirdParameter );
  683. strcpy( szBuffer, szOriginalBuffer );
  684. csThirdParameter.MakeLower();
  685. BOOL bFoundInMap = m_mapCriticalSection.Lookup( csThirdParameter, (CString&) csOwningThread );
  686. //If not found in map,
  687. if ( !bFoundInMap ) {
  688. csOutput.Format( _T("Thread %s id: %s is in WaitForCriticalSection() call on object %s"), csThreadNumber, csThreadID, csThirdParameter );
  689. bFound = TRUE;
  690. break;
  691. }
  692. else {
  693. csOutput.Format( _T("Thread %s id: %s is in WaitForCriticalSection() call on object %s. Thread %s is the owning thread."), csThreadNumber, csThreadID, csThirdParameter, csOwningThread);
  694. bFound = TRUE;
  695. break;
  696. }
  697. }
  698. else if ( strstr( szBuffer, gslWaitForMultipleObjects ) ) {
  699. GetFirstParameter( szBuffer, csFirstParameter );
  700. strcpy( szBuffer, szOriginalBuffer );
  701. GetSecondParameter( szBuffer, csSecondParameter );
  702. strcpy( szBuffer, szOriginalBuffer );
  703. csOutput.Format( _T("Thread %s id: %s is in a WaitForMultipleObjects() call on %s objects at address %s"), csThreadNumber, csThreadID, csFirstParameter, csSecondParameter );
  704. bFound = TRUE;
  705. break;
  706. }
  707. else {
  708. csOutput.Format( _T("Thread %s is not in a known wait state"), csThreadNumber );
  709. bFound = TRUE;
  710. break;
  711. }
  712. if ( !bFound ) break;
  713. bFound = FALSE;
  714. } while ( TRUE );
  715. if ( !bFound ) break;
  716. bFound = FALSE;
  717. //Output the text to the list control
  718. m_ctlListControl.AddString( csOutput );
  719. } while ( TRUE );
  720. if ( !bFound ) break;
  721. bFound = FALSE;
  722. } while ( TRUE );
  723. }
  724. //
  725. // a-mando
  726. //
  727. void CReadLogsDlg::ResizeAndReposControl()
  728. {
  729. CRect rtListCtrl,
  730. rtHangInfo,
  731. rtDlg;
  732. GetWindowRect( &rtDlg );
  733. m_staticHangInfo.GetWindowRect( &rtHangInfo );
  734. m_ctlListControl.GetWindowRect( &rtListCtrl );
  735. ScreenToClient( &rtDlg );
  736. ScreenToClient( &rtHangInfo );
  737. ScreenToClient( &rtListCtrl );
  738. switch ( m_eReadLogType ) {
  739. case ReadLogsType_Exception:
  740. break;
  741. case ReadLogsType_Hang:
  742. m_staticHangInfo.ShowWindow(SW_SHOW);
  743. rtListCtrl.left = rtDlg.left + DLG_PIXEL_EXTEND_SIZE;
  744. rtListCtrl.top = rtHangInfo.bottom + DLG_PIXEL_EXTEND_SIZE;
  745. m_ctlListControl.MoveWindow(&rtListCtrl);
  746. m_ctlListControl.ShowWindow(SW_SHOW);
  747. break;
  748. case ReadLogsType_None:
  749. //Disable all the controls
  750. break;
  751. }
  752. }
  753. // a-mando