Leaked source code of windows server 2003
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.

1282 lines
36 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. tracedmp.cpp
  5. Abstract:
  6. Sample trace consumer program. Converts binary Event Trace Log (ETL) to CSV format.
  7. Aside from various printing routines for dumping event data and writing summary,
  8. three functions need mentioning. main() parses command line and calls OpenTrace(),
  9. ProcessTrace(), and CloseTrace(). BufferCallback() is for BufferCallback and
  10. simply counts the number of buffers processed. Finally, DumpEvent() is the
  11. EventCallback function in this sample that writes event data into a dumpfile.
  12. Important Notes:
  13. Event Tracing API for trace consumption (OpenTrace, ProcessTrace, CloseTrace,...)
  14. are straightforward and easy to use. Hence, getting an event back is simple.
  15. However, another important aspect of trace consumption is event decoding, which
  16. requires event layout information. This information may be known in advance and
  17. hard coded in an event consumer, but we rely on WMI name space for storing event
  18. layout information. This requires extensive WMI interface just to get the layout.
  19. We placed all the routines needed for getting layout information in a separate
  20. file (tracewmi.cpp). The only two functions exported from this file are
  21. GetMofInfoHead() and RemoveMofInfo(). GetMofInfoHead() is the one that returns
  22. MOF_INFO with the proper layout information. RemoveMofInfo() is used only for
  23. cleaning up cached event list.
  24. We hope this helps readers understand two separate issues in this samples:
  25. event tracing APIs and WMI interface.
  26. --*/
  27. #include "tracedmp.h"
  28. extern
  29. PMOF_INFO
  30. GetMofInfoHead(
  31. GUID Guid,
  32. SHORT nType,
  33. SHORT nVersion,
  34. CHAR nLevel
  35. );
  36. extern
  37. void
  38. RemoveMofInfo(
  39. PLIST_ENTRY pMofInfo
  40. );
  41. // Simple check on a trace file.
  42. ULONG
  43. CheckFile(
  44. LPTSTR fileName
  45. );
  46. // BufferCallback function.
  47. ULONG
  48. WINAPI
  49. BufferCallback(
  50. PEVENT_TRACE_LOGFILE pLog
  51. );
  52. // EventCallback function in this sample.
  53. void
  54. WINAPI
  55. DumpEvent(
  56. PEVENT_TRACE pEvent
  57. );
  58. // Print functions
  59. void
  60. PrintSummary();
  61. void
  62. PrintDumpHeader();
  63. void
  64. PrintEvent(
  65. PEVENT_TRACE pEvent,
  66. PMOF_INFO pMofInfo
  67. );
  68. // Other helper functions.
  69. void
  70. GuidToString(
  71. PTCHAR s,
  72. LPGUID piid
  73. );
  74. void
  75. PrintHelpMessage();
  76. void
  77. CleanupEventList(
  78. VOID
  79. );
  80. // output files
  81. FILE* DumpFile = NULL;
  82. FILE* SummaryFile = NULL;
  83. static ULONG TotalBuffersRead = 0;
  84. static ULONG TotalEventsLost = 0;
  85. static ULONG TotalEventCount = 0;
  86. static ULONG TimerResolution = 10;
  87. static ULONGLONG StartTime = 0;
  88. static ULONGLONG EndTime = 0;
  89. static BOOL fNoEndTime = FALSE;
  90. static __int64 ElapseTime;
  91. // Option flags.
  92. BOOLEAN fSummaryOnly = FALSE;
  93. // Sizeof of a pointer in a file may be different.
  94. ULONG PointerSize = sizeof(PVOID) * 8;
  95. // log files
  96. PEVENT_TRACE_LOGFILE EvmFile[MAXLOGFILES];
  97. ULONG LogFileCount = 0;
  98. // IF the events are from a private logger, we need to make some adjustment.
  99. BOOL bUserMode = FALSE;
  100. // Global head for event layout linked list
  101. PLIST_ENTRY EventListHead = NULL;
  102. int __cdecl main (int argc, LPTSTR* argv)
  103. /*++
  104. Routine Description:
  105. It is the main function.
  106. Arguments:
  107. Usage: tracedmp [options] <EtlFile1 EtlFile2 ...>| [-h | -? | -help]
  108. -o <file> Output CSV file
  109. -rt [LoggerName] Realtime tracedmp from the logger [LoggerName]
  110. -summary Summary.txt only
  111. -h
  112. -help
  113. -? Display usage information
  114. Return Value:
  115. Error Code defined in winerror.h : If the function succeeds,
  116. it returns ERROR_SUCCESS (== 0).
  117. --*/
  118. {
  119. TCHAR DumpFileName[MAXSTR];
  120. TCHAR SummaryFileName[MAXSTR];
  121. LPTSTR *targv;
  122. #ifdef UNICODE
  123. LPTSTR *cmdargv;
  124. #endif
  125. PEVENT_TRACE_LOGFILE pLogFile;
  126. ULONG Status = ERROR_SUCCESS;
  127. ULONG i, j;
  128. TRACEHANDLE HandleArray[MAXLOGFILES];
  129. #ifdef UNICODE
  130. if ((cmdargv = CommandLineToArgvW(
  131. GetCommandLineW(), // pointer to a command-line string
  132. &argc // receives the argument count
  133. )) == NULL)
  134. {
  135. return(GetLastError());
  136. };
  137. targv = cmdargv ;
  138. #else
  139. targv = argv;
  140. #endif
  141. _tcscpy(DumpFileName, DUMP_FILE_NAME);
  142. _tcscpy(SummaryFileName, SUMMARY_FILE_NAME);
  143. while (--argc > 0) {
  144. ++targv;
  145. if (**targv == '-' || **targv == '/') { // argument found
  146. if( **targv == '/' ){
  147. **targv = '-';
  148. }
  149. if ( !_tcsicmp(targv[0], _T("-summary")) ) {
  150. fSummaryOnly = TRUE;
  151. }
  152. else if (targv[0][1] == 'h' || targv[0][1] == 'H'
  153. || targv[0][1] == '?')
  154. {
  155. PrintHelpMessage();
  156. return ERROR_SUCCESS;
  157. }
  158. else if ( !_tcsicmp(targv[0], _T("-rt")) ) {
  159. TCHAR LoggerName[MAXSTR];
  160. _tcscpy(LoggerName, KERNEL_LOGGER_NAME);
  161. if (argc > 1) {
  162. if (targv[1][0] != '-' && targv[1][0] != '/') {
  163. ++targv; --argc;
  164. _tcscpy(LoggerName, targv[0]);
  165. }
  166. }
  167. pLogFile = (PEVENT_TRACE_LOGFILE) malloc(sizeof(EVENT_TRACE_LOGFILE));
  168. if (pLogFile == NULL){
  169. _tprintf(_T("Allocation Failure\n"));
  170. Status = ERROR_OUTOFMEMORY;
  171. goto cleanup;
  172. }
  173. RtlZeroMemory(pLogFile, sizeof(EVENT_TRACE_LOGFILE));
  174. EvmFile[LogFileCount] = pLogFile;
  175. EvmFile[LogFileCount]->LogFileName = NULL;
  176. EvmFile[LogFileCount]->LoggerName =
  177. (LPTSTR) malloc(MAXSTR * sizeof(TCHAR));
  178. if (EvmFile[LogFileCount]->LoggerName == NULL) {
  179. _tprintf(_T("Allocation Failure\n"));
  180. Status = ERROR_OUTOFMEMORY;
  181. goto cleanup;
  182. }
  183. _tcscpy(EvmFile[LogFileCount]->LoggerName, LoggerName);
  184. _tprintf(_T("Setting RealTime mode for %s\n"),
  185. EvmFile[LogFileCount]->LoggerName);
  186. EvmFile[LogFileCount]->Context = NULL;
  187. EvmFile[LogFileCount]->BufferCallback = BufferCallback;
  188. EvmFile[LogFileCount]->BuffersRead = 0;
  189. EvmFile[LogFileCount]->CurrentTime = 0;
  190. EvmFile[LogFileCount]->EventCallback = &DumpEvent;
  191. EvmFile[LogFileCount]->LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
  192. LogFileCount++;
  193. }
  194. else if ( !_tcsicmp(targv[0], _T("-o")) ) {
  195. if (argc > 1) {
  196. if (targv[1][0] != '-' && targv[1][0] != '/') {
  197. TCHAR drive[10];
  198. TCHAR path[MAXSTR];
  199. TCHAR file[MAXSTR];
  200. TCHAR ext[MAXSTR];
  201. ++targv; --argc;
  202. _tfullpath(DumpFileName, targv[0], MAXSTR);
  203. _tsplitpath( DumpFileName, drive, path, file, ext );
  204. _tcscpy(ext,_T("csv"));
  205. _tmakepath( DumpFileName, drive, path, file, ext );
  206. _tcscpy(ext,_T("txt"));
  207. _tmakepath( SummaryFileName, drive, path, file, ext );
  208. }
  209. }
  210. }
  211. }
  212. else {
  213. pLogFile = (PEVENT_TRACE_LOGFILE) malloc(sizeof(EVENT_TRACE_LOGFILE));
  214. if (pLogFile == NULL){
  215. _tprintf(_T("Allocation Failure\n"));
  216. Status = ERROR_OUTOFMEMORY;
  217. goto cleanup;
  218. }
  219. RtlZeroMemory(pLogFile, sizeof(EVENT_TRACE_LOGFILE));
  220. EvmFile[LogFileCount] = pLogFile;
  221. EvmFile[LogFileCount]->LoggerName = NULL;
  222. EvmFile[LogFileCount]->LogFileName =
  223. (LPTSTR) malloc(MAXSTR*sizeof(TCHAR));
  224. if (EvmFile[LogFileCount]->LogFileName == NULL) {
  225. _tprintf(_T("Allocation Failure\n"));
  226. Status = ERROR_OUTOFMEMORY;
  227. goto cleanup;
  228. }
  229. _tfullpath(EvmFile[LogFileCount]->LogFileName, targv[0], MAXSTR);
  230. _tprintf(_T("Setting log file to: %s\n"),
  231. EvmFile[LogFileCount]->LogFileName);
  232. // If one of the log files is not readable, exit.
  233. if (!CheckFile(EvmFile[LogFileCount]->LogFileName)) {
  234. _tprintf(_T("Cannot open logfile for reading\n"));
  235. Status = ERROR_INVALID_PARAMETER;
  236. goto cleanup;
  237. }
  238. EvmFile[LogFileCount]->Context = NULL;
  239. EvmFile[LogFileCount]->BufferCallback = BufferCallback;
  240. EvmFile[LogFileCount]->BuffersRead = 0;
  241. EvmFile[LogFileCount]->CurrentTime = 0;
  242. EvmFile[LogFileCount]->EventCallback = &DumpEvent;
  243. LogFileCount++;
  244. }
  245. }
  246. if (LogFileCount <= 0) {
  247. PrintHelpMessage();
  248. return Status;
  249. }
  250. // OpenTrace calls
  251. for (i = 0; i < LogFileCount; i++) {
  252. TRACEHANDLE x;
  253. x = OpenTrace(EvmFile[i]);
  254. HandleArray[i] = x;
  255. if (HandleArray[i] == 0) {
  256. Status = GetLastError();
  257. _tprintf(_T("Error Opening Trace %d with status=%d\n"),
  258. i, Status);
  259. for (j = 0; j < i; j++)
  260. CloseTrace(HandleArray[j]);
  261. goto cleanup;
  262. }
  263. }
  264. // Open files.
  265. if (!fSummaryOnly)
  266. {
  267. DumpFile = _tfopen(DumpFileName, _T("w"));
  268. if (DumpFile == NULL) {
  269. Status = ERROR_INVALID_PARAMETER;
  270. _tprintf(_T("DumpFile is NULL\n"));
  271. goto cleanup;
  272. }
  273. }
  274. SummaryFile = _tfopen(SummaryFileName, _T("w"));
  275. if (SummaryFile == NULL) {
  276. Status = ERROR_INVALID_PARAMETER;
  277. _tprintf(_T("SummaryFile is NULL\n"));
  278. goto cleanup;
  279. }
  280. if (!fSummaryOnly)
  281. {
  282. PrintDumpHeader();
  283. }
  284. // At this point, users can set a different trace callback function for
  285. // a specific GUID using SetTraceCallback(). Also RemoveTraceCallback() allows
  286. // users to remove a callback function for a specific GUID. In this way, users
  287. // can customize callbacks based on GUIDs.
  288. // Actual processing takes place here. EventCallback function will be invoked
  289. // for each event.
  290. // We do not use start and end time parameters in this sample.
  291. Status = ProcessTrace(
  292. HandleArray,
  293. LogFileCount,
  294. NULL,
  295. NULL
  296. );
  297. if (Status != ERROR_SUCCESS) {
  298. _tprintf(_T("Error processing with status=%dL (GetLastError=0x%x)\n"),
  299. Status, GetLastError());
  300. }
  301. for (j = 0; j < LogFileCount; j++){
  302. Status = CloseTrace(HandleArray[j]);
  303. if (Status != ERROR_SUCCESS) {
  304. _tprintf(_T("Error Closing Trace %d with status=%d\n"), j, Status);
  305. }
  306. }
  307. // Write summary.
  308. PrintSummary();
  309. cleanup:
  310. if (!fSummaryOnly && DumpFile != NULL) {
  311. _tprintf(_T("Event traces dumped to %s\n"), DumpFileName);
  312. fclose(DumpFile);
  313. }
  314. if(SummaryFile != NULL){
  315. _tprintf(_T("Event Summary dumped to %s\n"), SummaryFileName);
  316. fclose(SummaryFile);
  317. }
  318. for (i = 0; i < LogFileCount; i ++)
  319. {
  320. if (EvmFile[i]->LoggerName != NULL)
  321. {
  322. free(EvmFile[i]->LoggerName);
  323. EvmFile[i]->LoggerName = NULL;
  324. }
  325. if (EvmFile[i]->LogFileName != NULL)
  326. {
  327. free(EvmFile[i]->LogFileName);
  328. EvmFile[i]->LogFileName = NULL;
  329. }
  330. free(EvmFile[i]);
  331. }
  332. #ifdef UNICODE
  333. GlobalFree(cmdargv);
  334. #endif
  335. SetLastError(Status);
  336. if(Status != ERROR_SUCCESS ){
  337. _tprintf(_T("Exit Status: %d\n"), Status);
  338. }
  339. return Status;
  340. }
  341. ULONG
  342. WINAPI
  343. BufferCallback(
  344. PEVENT_TRACE_LOGFILE pLog
  345. )
  346. /*++
  347. Routine Description:
  348. Callback method for processing a buffer. Does not do anything but
  349. updating global counters.
  350. Arguments:
  351. pLog - Pointer to a log file.
  352. Return Value:
  353. Always TRUE.
  354. --*/
  355. {
  356. TotalBuffersRead++;
  357. return (TRUE);
  358. }
  359. void
  360. WINAPI
  361. DumpEvent(
  362. PEVENT_TRACE pEvent
  363. )
  364. /*++
  365. Routine Description:
  366. Callback method for processing an event. It obtains the layout
  367. information by calling GetMofInfoHead(), which returns the pointer
  368. to the PMOF_INFO corresponding to the event type. Then it writes
  369. to the output file.
  370. NOTE: Only character arrays are supported in this program.
  371. Arguments:
  372. pEvent - Pointer to an event.
  373. Return Value:
  374. None.
  375. --*/
  376. {
  377. PEVENT_TRACE_HEADER pHeader;
  378. PMOF_INFO pMofInfo;
  379. TotalEventCount++;
  380. if (pEvent == NULL) {
  381. _tprintf(_T("Warning: Null Event\n"));
  382. return;
  383. }
  384. pHeader = (PEVENT_TRACE_HEADER) &pEvent->Header;
  385. // Extrace log file information if the event is a log file header.
  386. if( IsEqualGUID(&(pEvent->Header.Guid), &EventTraceGuid) &&
  387. pEvent->Header.Class.Type == EVENT_TRACE_TYPE_INFO ) {
  388. PTRACE_LOGFILE_HEADER head = (PTRACE_LOGFILE_HEADER)pEvent->MofData;
  389. if( NULL != head ){
  390. if(head->TimerResolution > 0){
  391. TimerResolution = head->TimerResolution / 10000;
  392. }
  393. StartTime = head->StartTime.QuadPart;
  394. EndTime = head->EndTime.QuadPart;
  395. // If ProcessTrace() call was made on areal time logger or an trace file being
  396. // logged, EndTime amy be 0.
  397. fNoEndTime = (EndTime == 0);
  398. TotalEventsLost += head->EventsLost;
  399. // We use global flags for private logger and pointer size.
  400. // This may cause an error when trace files are from different environments.
  401. bUserMode = (head->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE);
  402. // Set pointer size
  403. PointerSize = head->PointerSize * 8;
  404. if (PointerSize != 64){
  405. PointerSize = 32;
  406. }
  407. }
  408. }
  409. // if EndTime is missing from one of the files, keep updating to get the largest value.
  410. if (fNoEndTime && EndTime < (ULONGLONG) pHeader->TimeStamp.QuadPart) {
  411. EndTime = pHeader->TimeStamp.QuadPart;
  412. }
  413. // Find the MOF information for this event. This will retrieve the layout
  414. // information from WMI fi we don't already have it in our list.
  415. pMofInfo = GetMofInfoHead (
  416. pEvent->Header.Guid,
  417. pEvent->Header.Class.Type,
  418. pEvent->Header.Class.Version,
  419. pEvent->Header.Class.Level
  420. );
  421. if( NULL == pMofInfo ){
  422. // Could not locate event layout information.
  423. return;
  424. }
  425. pMofInfo->EventCount++;
  426. if( fSummaryOnly == TRUE ){
  427. return;
  428. }
  429. // At this point, pEvent and pMofInfo are not NULL. No need to check in PrintEvent().
  430. PrintEvent(pEvent, pMofInfo);
  431. }
  432. /***************************************************************************************
  433. Various printing and helper function after this point.
  434. ***************************************************************************************/
  435. void PrintDumpHeader()
  436. /*++
  437. Routine Description:
  438. Prints out column headers to a dump file.
  439. Arguments:
  440. None
  441. Return Value:
  442. None
  443. --*/
  444. {
  445. _ftprintf(DumpFile,
  446. _T("%12s, %10s,%7s,%21s,%11s,%11s, User Data\n"),
  447. _T("Event Name"), _T("Type"), _T("TID"), _T("Clock-Time"),
  448. _T("Kernel(ms)"), _T("User(ms)")
  449. );
  450. }
  451. void PrintSummary()
  452. /*++
  453. Routine Description:
  454. Prints out a event summary into a dump file while cleaning the event list.
  455. Arguments:
  456. None
  457. Return Value:
  458. None
  459. --*/
  460. {
  461. ULONG i;
  462. _ftprintf(SummaryFile,_T("Files Processed:\n"));
  463. for (i = 0; i < LogFileCount; i++) {
  464. _ftprintf(SummaryFile, _T("\t%s\n"),EvmFile[i]->LogFileName);
  465. }
  466. ElapseTime = EndTime - StartTime;
  467. _ftprintf(SummaryFile,
  468. _T("Total Buffers Processed %d\n")
  469. _T("Total Events Processed %d\n")
  470. _T("Total Events Lost %d\n")
  471. _T("Start Time 0x%016I64X\n")
  472. _T("End Time 0x%016I64X\n")
  473. _T("Elapsed Time %I64d sec\n"),
  474. TotalBuffersRead,
  475. TotalEventCount,
  476. TotalEventsLost,
  477. StartTime,
  478. EndTime,
  479. (ElapseTime / 10000000) );
  480. _ftprintf(SummaryFile,
  481. _T("+-------------------------------------------------------------------------------------+\n")
  482. _T("|%10s %-20s %-10s %-36s |\n")
  483. _T("+-------------------------------------------------------------------------------------+\n"),
  484. _T("EventCount"),
  485. _T("EventName"),
  486. _T("EventType"),
  487. _T("Guid")
  488. );
  489. // Print event GUIDs while cleaning up.
  490. CleanupEventList();
  491. _ftprintf(SummaryFile,
  492. _T("+-------------------------------------------------------------------------------------+\n")
  493. );
  494. }
  495. void
  496. PrintEvent(
  497. PEVENT_TRACE pEvent,
  498. PMOF_INFO pMofInfo
  499. )
  500. /*++
  501. Routine Description:
  502. Dumps event data into a dump file.
  503. Arguments:
  504. None
  505. Return Value:
  506. None
  507. --*/
  508. {
  509. PEVENT_TRACE_HEADER pHeader = (PEVENT_TRACE_HEADER) &pEvent->Header;
  510. ULONG i;
  511. PITEM_DESC pItem;
  512. CHAR str[MOFSTR];
  513. WCHAR wstr[MOFWSTR];
  514. PCHAR ptr;
  515. ULONG ulongword;
  516. LONG longword;
  517. USHORT ushortword;
  518. SHORT shortword;
  519. CHAR iChar;
  520. WCHAR iwChar;
  521. ULONG MofDataUsed;
  522. PLIST_ENTRY Head, Next;
  523. // Print a general information on the event.
  524. if ( pMofInfo->strDescription != NULL ){
  525. _ftprintf( DumpFile, _T("%12s, "), pMofInfo->strDescription );
  526. }
  527. else {
  528. TCHAR strGuid[MAXSTR];
  529. GuidToString( strGuid, &pMofInfo->Guid );
  530. _ftprintf( DumpFile, _T("%12s, "), strGuid );
  531. }
  532. if (pMofInfo->strType != NULL && _tcslen(pMofInfo->strType) ){
  533. _ftprintf( DumpFile, _T("%10s, "), pMofInfo->strType );
  534. }
  535. else {
  536. _ftprintf( DumpFile, _T("%10d, "), pEvent->Header.Class.Type );
  537. }
  538. // Thread ID
  539. _ftprintf( DumpFile, _T("0x%04X, "), pHeader->ThreadId );
  540. // System Time
  541. _ftprintf( DumpFile, _T("%20I64u, "), pHeader->TimeStamp.QuadPart);
  542. if ( bUserMode == FALSE ){
  543. // Kernel Time
  544. _ftprintf(DumpFile, _T("%10lu, "), pHeader->KernelTime * TimerResolution);
  545. // User Time
  546. _ftprintf(DumpFile, _T("%10lu, "), pHeader->UserTime * TimerResolution);
  547. }
  548. else {
  549. // processor Time
  550. _ftprintf(DumpFile, _T("%I64u, "), pHeader->ProcessorTime);
  551. }
  552. if (NULL == pEvent->MofData && pEvent->MofLength != 0) {
  553. _tprintf(_T("Incorrect MOF size\n"));
  554. return;
  555. }
  556. Head = pMofInfo->ItemHeader;
  557. Next = Head->Flink;
  558. ptr = (PCHAR)(pEvent->MofData);
  559. // If we cannot locate layout information, just print the size.
  560. if ((Head == Next) && (pEvent->MofLength > 0)) {
  561. _ftprintf(DumpFile, _T("DataSize=%d, "), pEvent->MofLength);
  562. }
  563. // Print event-specific data.
  564. while (Head != Next) {
  565. pItem = CONTAINING_RECORD(Next, ITEM_DESC, Entry);
  566. Next = Next->Flink;
  567. MofDataUsed = (ULONG) (ptr - (PCHAR)(pEvent->MofData));
  568. if (MofDataUsed >= pEvent->MofLength){
  569. break;
  570. }
  571. switch (pItem->ItemType)
  572. {
  573. case ItemChar: // char
  574. case ItemUChar: // unsigned char
  575. for( i = 0; i < pItem->ArraySize; i++){
  576. iChar = *((PCHAR) ptr);
  577. _ftprintf(DumpFile, _T("%c"), iChar);
  578. ptr += sizeof(CHAR);
  579. }
  580. _ftprintf(DumpFile, _T(", "));
  581. break;
  582. case ItemWChar: // wide char
  583. for(i = 0;i < pItem->ArraySize; i++){
  584. iwChar = *((PWCHAR) ptr);
  585. _ftprintf(DumpFile, _T(",%wc"), iwChar);
  586. ptr += sizeof(WCHAR);
  587. }
  588. _ftprintf(DumpFile, _T(", "));
  589. break;
  590. case ItemCharShort: // char as a number
  591. iChar = *((PCHAR) ptr);
  592. _ftprintf(DumpFile, _T("%d, "), iChar);
  593. ptr += sizeof(CHAR);
  594. break;
  595. case ItemShort: // short
  596. shortword = * ((PSHORT) ptr);
  597. _ftprintf(DumpFile, _T("%6d, "), shortword);
  598. ptr += sizeof (SHORT);
  599. break;
  600. case ItemUShort: // unsigned short
  601. ushortword = *((PUSHORT) ptr);
  602. _ftprintf(DumpFile, _T("%6u, "), ushortword);
  603. ptr += sizeof (USHORT);
  604. break;
  605. case ItemLong: // long
  606. longword = *((PLONG) ptr);
  607. _ftprintf(DumpFile, _T("%8d, "), longword);
  608. ptr += sizeof (LONG);
  609. break;
  610. case ItemULong: // unsigned long
  611. ulongword = *((PULONG) ptr);
  612. _ftprintf(DumpFile, _T("%8lu, "), ulongword);
  613. ptr += sizeof (ULONG);
  614. break;
  615. case ItemULongX: // unsinged long as hex
  616. ulongword = *((PULONG) ptr);
  617. _ftprintf(DumpFile, _T("0x%08X, "), ulongword);
  618. ptr += sizeof (ULONG);
  619. break;
  620. case ItemLongLong:
  621. {
  622. LONGLONG n64; // longlong
  623. n64 = *((LONGLONG*) ptr);
  624. ptr += sizeof(LONGLONG);
  625. _ftprintf(DumpFile, _T("%16I64d, "), n64);
  626. break;
  627. }
  628. case ItemULongLong: // unsigned longlong
  629. {
  630. ULONGLONG n64;
  631. n64 = *((ULONGLONG*) ptr);
  632. ptr += sizeof(ULONGLONG);
  633. _ftprintf(DumpFile, _T("%16I64u, "), n64);
  634. break;
  635. }
  636. case ItemFloat: // float
  637. {
  638. float f32;
  639. f32 = *((float*) ptr);
  640. ptr += sizeof(float);
  641. _ftprintf(DumpFile, _T("%f, "), f32);
  642. break;
  643. }
  644. case ItemDouble: // double
  645. {
  646. double f64;
  647. f64 = *((double*) ptr);
  648. ptr += sizeof(double);
  649. _ftprintf(DumpFile, _T("%f, "), f64);
  650. break;
  651. }
  652. case ItemPtr : // pointer
  653. {
  654. unsigned __int64 pointer;
  655. if (PointerSize == 64) {
  656. pointer = *((unsigned __int64 *) ptr);
  657. _ftprintf(DumpFile, _T("0x%X, "), pointer);
  658. ptr += 8;
  659. }
  660. else { // assumes 32 bit otherwise
  661. ulongword = *((PULONG) ptr);
  662. _ftprintf(DumpFile, _T("0x%08X, "), ulongword);
  663. ptr += 4;
  664. }
  665. break;
  666. }
  667. case ItemIPAddr: // IP address
  668. {
  669. ulongword = *((PULONG) ptr);
  670. // Convert it to readable form
  671. _ftprintf(DumpFile, _T("%03d.%03d.%03d.%03d, "),
  672. (ulongword >> 0) & 0xff,
  673. (ulongword >> 8) & 0xff,
  674. (ulongword >> 16) & 0xff,
  675. (ulongword >> 24) & 0xff);
  676. ptr += sizeof (ULONG);
  677. break;
  678. }
  679. case ItemPort: // Port
  680. {
  681. _ftprintf(DumpFile, _T("%u, "), NTOHS(*((PUSHORT)ptr)));
  682. ptr += sizeof (USHORT);
  683. break;
  684. }
  685. case ItemString: // NULL-terminated char string
  686. {
  687. USHORT pLen = (USHORT)strlen((CHAR*) ptr);
  688. if (pLen > 0)
  689. {
  690. strcpy(str, ptr);
  691. for (i = pLen-1; i > 0; i--) {
  692. if (str[i] == 0xFF)
  693. str[i] = 0;
  694. else break;
  695. }
  696. #ifdef UNICODE
  697. MultiByteToWideChar(CP_ACP, 0, str, -1, wstr, MOFWSTR);
  698. _ftprintf(DumpFile, _T("\"%ws\","), wstr);
  699. #else
  700. _ftprintf(DumpFile, _T("\"%s\","), str);
  701. #endif
  702. }
  703. ptr += (pLen + 1);
  704. break;
  705. }
  706. case ItemWString: // NULL-terminated wide char string
  707. {
  708. size_t pLen = 0;
  709. size_t i;
  710. if (*(PWCHAR)ptr)
  711. {
  712. pLen = ((wcslen((PWCHAR)ptr) + 1) * sizeof(WCHAR));
  713. RtlCopyMemory(wstr, ptr, pLen);
  714. // Unused space in a buffer is filled with 0xFFFF.
  715. // Replace them with 0, just in case.
  716. for (i = (pLen / 2) - 1; i > 0; i--)
  717. {
  718. if (((USHORT) wstr[i] == (USHORT) 0xFFFF))
  719. {
  720. wstr[i] = (USHORT) 0;
  721. }
  722. else break;
  723. }
  724. wstr[pLen / 2] = wstr[(pLen / 2) + 1]= '\0';
  725. _ftprintf(DumpFile, _T("\"%ws\","), wstr);
  726. }
  727. ptr += pLen;
  728. break;
  729. }
  730. case ItemDSString: // Counted String
  731. {
  732. USHORT pLen = (USHORT)(256 * ((USHORT) * ptr) + ((USHORT) * (ptr + 1)));
  733. ptr += sizeof(USHORT);
  734. if (pLen > (pEvent->MofLength - MofDataUsed - 1)) {
  735. pLen = (USHORT) (pEvent->MofLength - MofDataUsed - 1);
  736. }
  737. if (pLen > 0)
  738. {
  739. strncpy(str, ptr, pLen);
  740. str[pLen] = '\0';
  741. #ifdef UNICODE
  742. MultiByteToWideChar(CP_ACP, 0, str, -1, wstr, MOFWSTR);
  743. fwprintf(DumpFile, _T("\"%ws\","), wstr);
  744. #else
  745. fprintf(DumpFile, _T("\"%s\","), str);
  746. #endif
  747. }
  748. ptr += (pLen + 1);
  749. break;
  750. }
  751. case ItemPString: // Counted String
  752. {
  753. USHORT pLen = * ((USHORT *) ptr);
  754. ptr += sizeof(USHORT);
  755. if (pLen > (pEvent->MofLength - MofDataUsed)) {
  756. pLen = (USHORT) (pEvent->MofLength - MofDataUsed);
  757. }
  758. if (pLen > MOFSTR * sizeof(CHAR)) {
  759. pLen = MOFSTR * sizeof(CHAR);
  760. }
  761. if (pLen > 0) {
  762. RtlCopyMemory(str, ptr, pLen);
  763. str[pLen] = '\0';
  764. #ifdef UNICODE
  765. MultiByteToWideChar(CP_ACP, 0, str, -1, wstr, MOFWSTR);
  766. _ftprintf(DumpFile, _T("\"%ws\","), wstr);
  767. #else
  768. _ftprintf(DumpFile, _T("\"%s\","), str);
  769. #endif
  770. }
  771. ptr += pLen;
  772. break;
  773. }
  774. case ItemDSWString: // DS Counted Wide Strings
  775. case ItemPWString: // Counted Wide Strings
  776. {
  777. USHORT pLen = (USHORT)(( pItem->ItemType == ItemDSWString)
  778. ? (256 * ((USHORT) * ptr) + ((USHORT) * (ptr + 1)))
  779. : (* ((USHORT *) ptr)));
  780. ptr += sizeof(USHORT);
  781. if (pLen > (pEvent->MofLength - MofDataUsed)) {
  782. pLen = (USHORT) (pEvent->MofLength - MofDataUsed);
  783. }
  784. if (pLen > MOFWSTR * sizeof(WCHAR)) {
  785. pLen = MOFWSTR * sizeof(WCHAR);
  786. }
  787. if (pLen > 0) {
  788. RtlCopyMemory(wstr, ptr, pLen);
  789. wstr[pLen / sizeof(WCHAR)] = L'\0';
  790. _ftprintf(DumpFile, _T("\"%ws\","), wstr);
  791. }
  792. ptr += pLen;
  793. break;
  794. }
  795. case ItemNWString: // Non Null Terminated String
  796. {
  797. USHORT Size;
  798. Size = (USHORT)(pEvent->MofLength - (ULONG)(ptr - (PCHAR)(pEvent->MofData)));
  799. if( Size > MOFSTR )
  800. {
  801. Size = MOFSTR;
  802. }
  803. if (Size > 0)
  804. {
  805. RtlCopyMemory(wstr, ptr, Size);
  806. wstr[Size / 2] = '\0';
  807. _ftprintf(DumpFile, _T("\"%ws\","), wstr);
  808. }
  809. ptr += Size;
  810. break;
  811. }
  812. case ItemMLString: // Multi Line String
  813. {
  814. USHORT pLen;
  815. char * src, * dest;
  816. BOOL inQ = FALSE;
  817. BOOL skip = FALSE;
  818. UINT lineCount = 0;
  819. ptr += sizeof(UCHAR) * 2;
  820. pLen = (USHORT)strlen(ptr);
  821. if (pLen > 0)
  822. {
  823. src = ptr;
  824. dest = str;
  825. while (* src != '\0'){
  826. if (* src == '\n'){
  827. if (!lineCount){
  828. * dest++ = ' ';
  829. }
  830. lineCount++;
  831. }else if (* src == '\"'){
  832. if (inQ){
  833. char strCount[32];
  834. char * cpy;
  835. sprintf(strCount, "{%dx}", lineCount);
  836. cpy = & strCount[0];
  837. while (* cpy != '\0'){
  838. * dest ++ = * cpy ++;
  839. }
  840. }
  841. inQ = !inQ;
  842. }else if (!skip){
  843. *dest++ = *src;
  844. }
  845. skip = (lineCount > 1 && inQ);
  846. src++;
  847. }
  848. *dest = '\0';
  849. #ifdef UNICODE
  850. MultiByteToWideChar(CP_ACP, 0, str, -1, wstr, MOFWSTR);
  851. _ftprintf(DumpFile, _T("\"%ws\","), wstr);
  852. #else
  853. _ftprintf(DumpFile, _T("\"%s\","), str);
  854. #endif
  855. }
  856. ptr += (pLen);
  857. break;
  858. }
  859. case ItemSid: // SID
  860. {
  861. WCHAR UserName[64];
  862. WCHAR Domain[64];
  863. WCHAR FullName[256];
  864. ULONG asize = 0;
  865. ULONG bsize = 0;
  866. ULONG SidMarker;
  867. SID_NAME_USE Se;
  868. ULONG nSidLength;
  869. RtlCopyMemory(&SidMarker, ptr, sizeof(ULONG));
  870. if (SidMarker == 0){
  871. ptr += 4;
  872. fwprintf(DumpFile, L"0, ");
  873. }
  874. else
  875. {
  876. if (PointerSize == 64) {
  877. ptr += 16; // skip the TOKEN_USER structure
  878. }
  879. else {
  880. ptr += 8; // skip the TOKEN_USER structure
  881. }
  882. nSidLength = 8 + (4*ptr[1]);
  883. asize = 64;
  884. bsize = 64;
  885. if (LookupAccountSidW(
  886. NULL,
  887. (PSID) ptr,
  888. (LPWSTR) & UserName[0],
  889. & asize,
  890. (LPWSTR) & Domain[0],
  891. & bsize,
  892. & Se))
  893. {
  894. LPWSTR pFullName = &FullName[0];
  895. swprintf(pFullName, L"\\\\%s\\%s", Domain, UserName);
  896. asize = (ULONG) lstrlenW(pFullName);
  897. if (asize > 0){
  898. fwprintf(DumpFile, L"\"%s\", ", pFullName);
  899. }
  900. }
  901. else
  902. {
  903. fwprintf(DumpFile, L"\"System\", " );
  904. }
  905. SetLastError( ERROR_SUCCESS );
  906. ptr += nSidLength;
  907. }
  908. break;
  909. }
  910. case ItemGuid: // GUID
  911. {
  912. TCHAR s[64];
  913. GuidToString(s, (LPGUID)ptr);
  914. _ftprintf(DumpFile, _T("%s, "), s);
  915. ptr += sizeof(GUID);
  916. break;
  917. }
  918. case ItemBool: // boolean
  919. {
  920. BOOL Flag = (BOOL)*ptr;
  921. _ftprintf(DumpFile, _T("%5s, "), (Flag) ? _T("TRUE") : _T("FALSE"));
  922. ptr += sizeof(BOOL);
  923. break;
  924. }
  925. default:
  926. ptr += sizeof (int);
  927. }
  928. }
  929. //Instance ID
  930. _ftprintf(DumpFile, _T("%d,"), pEvent->InstanceId);
  931. //Parent Instance ID
  932. _ftprintf(DumpFile, _T("%d\n"), pEvent->ParentInstanceId);
  933. }
  934. ULONG
  935. CheckFile(
  936. LPTSTR fileName
  937. )
  938. /*++
  939. Routine Description:
  940. Checks whether a file exists and is readable.
  941. Arguments:
  942. fileName - File name.
  943. Return Value:
  944. Non-zero if the file exists and is readable. Zero otherwise.
  945. --*/
  946. {
  947. HANDLE hFile;
  948. ULONG Status;
  949. hFile = CreateFile(
  950. fileName,
  951. GENERIC_READ,
  952. FILE_SHARE_READ | FILE_SHARE_WRITE,
  953. NULL,
  954. OPEN_EXISTING,
  955. FILE_ATTRIBUTE_NORMAL,
  956. NULL
  957. );
  958. Status = (hFile != INVALID_HANDLE_VALUE);
  959. CloseHandle(hFile);
  960. return Status;
  961. }
  962. void
  963. GuidToString(
  964. PTCHAR s,
  965. LPGUID piid
  966. )
  967. /*++
  968. Routine Description:
  969. Converts a GUID into a string.
  970. Arguments:
  971. s - String that will have the converted GUID.
  972. piid - GUID
  973. Return Value:
  974. None.
  975. --*/
  976. {
  977. _stprintf(s, _T("{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}"),
  978. piid->Data1, piid->Data2,
  979. piid->Data3,
  980. piid->Data4[0], piid->Data4[1],
  981. piid->Data4[2], piid->Data4[3],
  982. piid->Data4[4], piid->Data4[5],
  983. piid->Data4[6], piid->Data4[7]);
  984. return;
  985. }
  986. void
  987. PrintHelpMessage()
  988. /*++
  989. Routine Description:
  990. Prints out help messages.
  991. Arguments:
  992. None
  993. Return Value:
  994. None
  995. --*/
  996. {
  997. _tprintf(
  998. _T("Usage: tracedmp [options] <EtlFile1 EtlFile2 ...>| [-h | -? | -help]\n")
  999. _T("\t-o <file> Output CSV file\n")
  1000. _T("\t-rt [LoggerName] Realtime tracedmp from the logger [LoggerName]\n")
  1001. _T("\t-summary Summary.txt only\n")
  1002. _T("\t-h\n")
  1003. _T("\t-help\n")
  1004. _T("\t-? Display usage information\n")
  1005. _T("\n")
  1006. _T("\tDefault output file is dumpfile.csv\n")
  1007. );
  1008. }
  1009. void
  1010. CleanupEventList(
  1011. VOID
  1012. )
  1013. /*++
  1014. Routine Description:
  1015. Cleans up a global event list.
  1016. Arguments:
  1017. Return Value:
  1018. None.
  1019. --*/
  1020. {
  1021. PLIST_ENTRY Head, Next;
  1022. PMOF_INFO pMofInfo;
  1023. TCHAR s[256];
  1024. TCHAR wstr[256];
  1025. PTCHAR str;
  1026. if (EventListHead == NULL) {
  1027. return;
  1028. }
  1029. Head = EventListHead;
  1030. Next = Head->Flink;
  1031. while (Head != Next) {
  1032. RtlZeroMemory(&wstr, 256);
  1033. pMofInfo = CONTAINING_RECORD(Next, MOF_INFO, Entry);
  1034. if (pMofInfo->EventCount > 0) {
  1035. GuidToString(&s[0], &pMofInfo->Guid);
  1036. str = s;
  1037. if( pMofInfo->strDescription != NULL ){
  1038. _tcscpy( wstr, pMofInfo->strDescription );
  1039. }
  1040. _ftprintf(SummaryFile,_T("|%10d %-20s %-10s %36s|\n"),
  1041. pMofInfo->EventCount,
  1042. wstr,
  1043. pMofInfo->strType ? pMofInfo->strType : GUID_TYPE_DEFAULT,
  1044. str);
  1045. }
  1046. RemoveEntryList(&pMofInfo->Entry);
  1047. RemoveMofInfo(pMofInfo->ItemHeader);
  1048. free(pMofInfo->ItemHeader);
  1049. if (pMofInfo->strDescription != NULL)
  1050. free(pMofInfo->strDescription);
  1051. if (pMofInfo->strType != NULL)
  1052. free(pMofInfo->strType);
  1053. Next = Next->Flink;
  1054. free(pMofInfo);
  1055. }
  1056. free(EventListHead);
  1057. }