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.

4994 lines
147 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. tracedc.c
  5. Abstract:
  6. Basic data consumer APIs to process trace data directly from buffers.
  7. Author:
  8. 15-Sep-1997 JeePang
  9. Revision History:
  10. 18-Apr-2001 insungp
  11. Added asynchronopus IO for reading log files.
  12. Also replaced WmiGetFirstTraceOffset() calls with sizeof(WMI_BUFFER_HEADER).
  13. --*/
  14. #ifndef MEMPHIS
  15. #include "wmiump.h"
  16. #include "traceump.h"
  17. #include "evntrace.h"
  18. #include "tracelib.h"
  19. #define MAXSTR 1024
  20. extern ULONG WmiTraceAlignment;
  21. #ifdef DBG
  22. void
  23. WmipDumpEvent(
  24. PEVENT_TRACE pEvent
  25. );
  26. void
  27. WmipDumpGuid(
  28. LPGUID
  29. );
  30. void
  31. WmipDumpCallbacks();
  32. #endif
  33. #define KERNEL_LOGGER_CAPTION TEXT("NT Kernel Logger")
  34. #define DEFAULT_LOG_BUFFER_SIZE 1024
  35. #define MAXBUFFERS 1024
  36. #define MINBUFFERS 8
  37. #define MAX_KERNEL_TRACE_EVENTS 22 // Look at \nt\base\published\ntwmi.w for the event groups
  38. #define TRACE_HEADER_SYSTEM32 TRACE_HEADER_FLAG | TRACE_HEADER_EVENT_TRACE \
  39. | (TRACE_HEADER_TYPE_SYSTEM32 << 16)
  40. #define TRACE_HEADER_SYSTEM64 TRACE_HEADER_FLAG | TRACE_HEADER_EVENT_TRACE \
  41. | (TRACE_HEADER_TYPE_SYSTEM64 << 16)
  42. #define TRACE_HEADER_FULL TRACE_HEADER_FLAG | TRACE_HEADER_EVENT_TRACE \
  43. | (TRACE_HEADER_TYPE_FULL_HEADER << 16)
  44. #define TRACE_HEADER_INSTANCE TRACE_HEADER_FLAG | TRACE_HEADER_EVENT_TRACE \
  45. | (TRACE_HEADER_TYPE_INSTANCE << 16)
  46. #define DEFAULT_REALTIME_BUFFER_SIZE 32768
  47. #define MAXBUFFERS 1024
  48. #define MINBUFFERS 8
  49. //
  50. // If the tracelog instance is a realtime data feed instead of from a
  51. // tracefile, TRACELOG_REALTIME_CONTEXT is used to maintain the real time
  52. // buffers in a buffer pool.
  53. //
  54. typedef struct _TRACE_BUFFER_SPACE {
  55. ULONG Reserved; // amount of memory reserved
  56. ULONG Committed;
  57. PVOID Space;
  58. LIST_ENTRY FreeListHead;
  59. } TRACE_BUFFER_SPACE, *PTRACE_BUFFER_SPACE;
  60. typedef struct _TRACELOG_REALTIME_CONTEXT {
  61. ULONG BuffersProduced; // Number of Buffers to read
  62. ULONG BufferOverflow; // Number of Buffers missed by the consumer
  63. GUID InstanceGuid; // Logger Instance Guid
  64. HANDLE MoreDataEvent; // Event to signal there is more data in this stream
  65. PTRACE_BUFFER_SPACE WmipTraceBufferSpace;
  66. PWNODE_HEADER RealTimeBufferPool[MAXBUFFERS];
  67. } TRACELOG_REALTIME_CONTEXT, *PTRACELOG_REALTIME_CONTEXT;
  68. //
  69. // RealTime Free Buffer Pool is chained up as TRACE_BUFFER_HEADER
  70. //
  71. typedef struct _TRACE_BUFFER_HEADER {
  72. WNODE_HEADER Wnode;
  73. LIST_ENTRY Entry;
  74. } TRACE_BUFFER_HEADER, *PTRACE_BUFFER_HEADER;
  75. typedef struct _TRACERT_BUFFER_LIST_ENTRY {
  76. ULONG Size;
  77. LIST_ENTRY Entry;
  78. LIST_ENTRY BufferListHead;
  79. } TRACERT_BUFFER_LIST_ENTRY, *PTRACERT_BUFFER_LIST_ENTRY;
  80. //
  81. // This TraceHandleListHeadPtr should be the only real global
  82. // for ProcessTrace to be multithreaded
  83. //
  84. PLIST_ENTRY TraceHandleListHeadPtr = NULL;
  85. //
  86. // For kernel events we map the Grouptype to Guid transparently to the caller.
  87. // The mapping between GroupType and Guid is maintained by this structure.
  88. //
  89. typedef struct _TRACE_GUID_MAP { // used to map GroupType to Guid
  90. ULONG GroupType; // Group & Type
  91. GUID Guid; // Guid
  92. } TRACE_GUID_MAP, *PTRACE_GUID_MAP;
  93. PTRACE_GUID_MAP EventMapList = NULL; // Array mapping the Grouptype to Guids
  94. typedef struct _EVENT_GUID_MAP {
  95. LIST_ENTRY Entry;
  96. ULONGLONG GuidHandle;
  97. GUID Guid;
  98. } EVENT_GUID_MAP, *PEVENT_GUID_MAP;
  99. // List of Registered callbacks. One callback per Guid Only.
  100. PLIST_ENTRY EventCallbackListHead = NULL;
  101. typedef struct _EVENT_TRACE_CALLBACK {
  102. LIST_ENTRY Entry;
  103. GUID Guid;
  104. PEVENT_CALLBACK CallbackRoutine;
  105. } EVENT_TRACE_CALLBACK, *PEVENT_TRACE_CALLBACK;
  106. #define MAX_TRACE_BUFFER_CACHE_SIZE 29
  107. typedef struct _TRACE_BUFFER_CACHE_ENTRY {
  108. LONG Index;
  109. PVOID Buffer;
  110. } TRACE_BUFFER_CACHE_ENTRY, *PTRACE_BUFFER_CACHE_ENTRY;
  111. struct _TRACE_BUFFER_LIST_ENTRY;
  112. typedef struct _TRACE_BUFFER_LIST_ENTRY {
  113. struct _TRACE_BUFFER_LIST_ENTRY *Next;
  114. LONG FileOffset; // Offset in File of this Buffer
  115. ULONG BufferOffset; // Offset in Buffer for the current event
  116. ULONG Flags; // Flags on status of this buffer
  117. ULONG EventSize;
  118. ULONG ClientContext; // Alignment, ProcessorNumber
  119. ULONG TraceType; // Current Event Type
  120. EVENT_TRACE Event; // CurrentEvent of this Buffer
  121. } TRACE_BUFFER_LIST_ENTRY, *PTRACE_BUFFER_LIST_ENTRY;
  122. typedef struct _TRACELOG_CONTEXT {
  123. LIST_ENTRY Entry; // Keeps track of storage allocations.
  124. // Fields from HandleListEntry
  125. EVENT_TRACE_LOGFILEW Logfile;
  126. TRACEHANDLE TraceHandle;
  127. ULONG ConversionFlags; // Flags indicating event processing options
  128. LONG BufferBeingRead;
  129. OVERLAPPED AsynchRead;
  130. //
  131. // Fields Below this will be reset upon ProcessTrace exit.
  132. //
  133. BOOLEAN fProcessed;
  134. USHORT LoggerId; // Logger Id of this DataFeed.
  135. UCHAR IsRealTime; // Flag to tell if this feed is RT.
  136. UCHAR fGuidMapRead;
  137. LIST_ENTRY GuidMapListHead; // This is LogFile specific property
  138. //
  139. // For using PerfClock, we need to save startTime, Freq
  140. //
  141. ULONG UsePerfClock;
  142. ULONG CpuSpeedInMHz;
  143. LARGE_INTEGER PerfFreq; // Frequency from the LogFile
  144. LARGE_INTEGER StartTime; // Start Wall clock time
  145. LARGE_INTEGER StartPerfClock; // Start PerfClock value
  146. union
  147. {
  148. HANDLE Handle; // NT handle to logfile
  149. PTRACELOG_REALTIME_CONTEXT RealTimeCxt; // Ptr to Real Time Context
  150. };
  151. ULONG EndOfFile; // Flag to show whether this stream is still active.
  152. ULONG BufferSize;
  153. ULONG BufferCount;
  154. ULONG InitialSize;
  155. ULONG StartBuffer;
  156. PTRACE_BUFFER_LIST_ENTRY Root;
  157. PTRACE_BUFFER_LIST_ENTRY BufferList;
  158. PVOID BufferCacheSpace;
  159. TRACE_BUFFER_CACHE_ENTRY BufferCache[MAX_TRACE_BUFFER_CACHE_SIZE];
  160. } TRACELOG_CONTEXT, *PTRACELOG_CONTEXT;
  161. //
  162. // this structure is used only by WmipGetBuffersWrittenFromQuery() and
  163. // WmipCheckForRealTimeLoggers()
  164. //
  165. typedef struct _ETW_QUERY_PROPERTIES {
  166. EVENT_TRACE_PROPERTIES TraceProp;
  167. WCHAR LoggerName[MAXSTR];
  168. WCHAR LogFileName[MAXSTR];
  169. } ETW_QUERY_PROPERTIES, *PETW_QUERY_PROPERTIES;
  170. ETW_QUERY_PROPERTIES Properties;
  171. ULONG
  172. WmipConvertEnumToTraceType(
  173. WMI_HEADER_TYPE eTraceType
  174. );
  175. WMI_HEADER_TYPE
  176. WmipConvertTraceTypeToEnum(
  177. ULONG TraceType
  178. );
  179. ULONG
  180. WmipCheckForRealTimeLoggers(
  181. PEVENT_TRACE_LOGFILEW *Logfiles,
  182. ULONG LogfileCount,
  183. ULONG Unicode
  184. );
  185. ULONG
  186. WmipLookforRealTimeBuffers(
  187. PEVENT_TRACE_LOGFILEW logfile
  188. );
  189. ULONG
  190. WmipRealTimeCallback(
  191. IN PWNODE_HEADER Wnode,
  192. IN ULONG_PTR Context
  193. );
  194. void
  195. WmipFreeRealTimeContext(
  196. PTRACELOG_REALTIME_CONTEXT RTCxt
  197. );
  198. ULONG
  199. WmipSetupRealTimeContext(
  200. PTRACEHANDLE HandleArray,
  201. PEVENT_TRACE_LOGFILEW *Logfiles,
  202. ULONG LogfileCount
  203. );
  204. PVOID
  205. WmipAllocTraceBuffer(
  206. PTRACELOG_REALTIME_CONTEXT RTCxt,
  207. ULONG BufferSize
  208. );
  209. VOID
  210. WmipFreeTraceBuffer(
  211. PTRACELOG_REALTIME_CONTEXT RTCxt,
  212. PVOID Buffer
  213. );
  214. ULONG
  215. WmipProcessRealTimeTraces(
  216. PTRACEHANDLE HandleArray,
  217. PEVENT_TRACE_LOGFILEW *Logfiles,
  218. ULONG LogfileCount,
  219. LONGLONG StartTime,
  220. LONGLONG EndTime,
  221. ULONG Unicode
  222. );
  223. //
  224. // Routines used in this file only
  225. //
  226. ULONG
  227. WmipDoEventCallbacks(
  228. PEVENT_TRACE_LOGFILEW logfile,
  229. PEVENT_TRACE pEvent
  230. );
  231. ULONG
  232. WmipCreateGuidMapping(void);
  233. LPGUID
  234. WmipGuidMapHandleToGuid(
  235. PLIST_ENTRY GuidMapListHeadPtr,
  236. ULONGLONG GuidHandle
  237. );
  238. void
  239. WmipCleanupGuidMapList(
  240. PLIST_ENTRY GuidMapListHeadPtr
  241. );
  242. void
  243. WmipCleanupTraceLog(
  244. PTRACELOG_CONTEXT pEntry
  245. );
  246. VOID
  247. WmipGuidMapCallback(
  248. PLIST_ENTRY GuidMapListHeadPtr,
  249. PEVENT_TRACE pEvent
  250. );
  251. ULONG
  252. WmipProcessGuidMaps(
  253. PEVENT_TRACE_LOGFILEW *Logfiles,
  254. ULONG LogfileCount,
  255. ULONG Unicode
  256. );
  257. PEVENT_TRACE_CALLBACK
  258. WmipGetCallbackRoutine(
  259. LPGUID pGuid
  260. );
  261. VOID
  262. WmipFreeCallbackList();
  263. ULONG
  264. WmipProcessLogHeader(
  265. PTRACEHANDLE HandleArray,
  266. PEVENT_TRACE_LOGFILEW *Logfiles,
  267. ULONG LogfileCount,
  268. ULONG Unicode,
  269. ULONG bFree
  270. );
  271. ULONG
  272. WmipProcessTraceLog(
  273. PTRACEHANDLE HandleArray,
  274. PEVENT_TRACE_LOGFILEW *Logfiles,
  275. ULONG LogfileCount,
  276. LONGLONG StartTime,
  277. LONGLONG EndTime,
  278. ULONG Unicode
  279. );
  280. ULONG
  281. WmipParseTraceEvent(
  282. IN PTRACELOG_CONTEXT pContext,
  283. IN PVOID LogBuffer,
  284. IN ULONG Offset,
  285. IN WMI_HEADER_TYPE HeaderType,
  286. IN OUT PVOID EventInfo,
  287. IN ULONG EventInfoSize
  288. );
  289. ULONG
  290. WmipGetBuffersWrittenFromQuery(
  291. LPWSTR LoggerName
  292. );
  293. VOID
  294. WmipCopyLogHeader (
  295. IN PTRACE_LOGFILE_HEADER pLogFileHeader,
  296. IN PVOID MofData,
  297. IN ULONG MofLength,
  298. IN PWCHAR *LoggerName,
  299. IN PWCHAR *LogFileName,
  300. IN ULONG Unicode
  301. );
  302. VOID
  303. WmipInsertBuffer (
  304. PTRACE_BUFFER_LIST_ENTRY *Root,
  305. PTRACE_BUFFER_LIST_ENTRY NewEntry
  306. )
  307. /*++
  308. Routine Description:
  309. This routine inserts a buffer in a sorted list. The insertion
  310. is done based on the timestamp of the BufferHeader. If two buffers
  311. have the same timestamp, then the BufferIndex is used to resolve the tie.
  312. Arguments:
  313. Root - Pointer to the root of the LIST
  314. NewEntry - Entry being inserted
  315. Returned Value:
  316. None
  317. --*/
  318. {
  319. PTRACE_BUFFER_LIST_ENTRY Current, Prev;
  320. //
  321. // If List is empty, make the new entry the Root and return.
  322. //
  323. if (NewEntry == NULL) {
  324. return;
  325. }
  326. if (*Root == NULL) {
  327. *Root = NewEntry;
  328. NewEntry->Next = NULL;
  329. return;
  330. }
  331. //
  332. // Traverse the list and insert the NewEntry in order
  333. //
  334. Prev = NULL;
  335. Current = *Root;
  336. while (Current != NULL) {
  337. if ((ULONGLONG)NewEntry->Event.Header.TimeStamp.QuadPart < (ULONGLONG)Current->Event.Header.TimeStamp.QuadPart) {
  338. if (Prev != NULL) {
  339. Prev->Next = NewEntry;
  340. }
  341. else {
  342. *Root = NewEntry;
  343. }
  344. NewEntry->Next = Current;
  345. return;
  346. }
  347. else if ((ULONGLONG)NewEntry->Event.Header.TimeStamp.QuadPart == (ULONGLONG)Current->Event.Header.TimeStamp.QuadPart) {
  348. if (NewEntry->FileOffset < Current->FileOffset) {
  349. if (Prev != NULL) {
  350. Prev->Next = NewEntry;
  351. }
  352. else {
  353. *Root = NewEntry;
  354. }
  355. NewEntry->Next = Current;
  356. return;
  357. }
  358. }
  359. Prev = Current;
  360. Current = Current->Next;
  361. }
  362. if (Prev != NULL) {
  363. Prev->Next = NewEntry;
  364. NewEntry->Next = NULL;
  365. }
  366. #if DBG
  367. else {
  368. WmipAssert(Prev != NULL);
  369. }
  370. #endif
  371. return;
  372. }
  373. PTRACE_BUFFER_LIST_ENTRY
  374. WmipRemoveBuffer(
  375. PTRACE_BUFFER_LIST_ENTRY *Root
  376. )
  377. {
  378. PTRACE_BUFFER_LIST_ENTRY OldEntry = *Root;
  379. if (OldEntry == NULL)
  380. return NULL;
  381. *Root = OldEntry->Next;
  382. OldEntry->Next = NULL;
  383. return OldEntry;
  384. }
  385. PVOID
  386. WmipGetCurrentBuffer(
  387. PTRACELOG_CONTEXT pContext,
  388. PTRACE_BUFFER_LIST_ENTRY Current
  389. )
  390. {
  391. NTSTATUS Status;
  392. LONG FileOffset = (ULONG)Current->FileOffset;
  393. ULONG nBytesRead;
  394. LONG TableIndex;
  395. HANDLE hFile = pContext->Handle;
  396. ULONG BufferSize = pContext->BufferSize;
  397. PVOID pBuffer;
  398. ULONGLONG Offset;
  399. DWORD BytesTransffered;
  400. //
  401. // Look for the buffer in cache.
  402. //
  403. TableIndex = FileOffset % MAX_TRACE_BUFFER_CACHE_SIZE;
  404. if (pContext->BufferCache[TableIndex].Index == FileOffset) {
  405. //
  406. // Check whether the buffer we want is still being read.
  407. // If so, we need to wait for it to finish.
  408. //
  409. if (pContext->BufferBeingRead == FileOffset) {
  410. if (GetOverlappedResult(hFile, &pContext->AsynchRead, &BytesTransffered, TRUE)) {
  411. pContext->BufferBeingRead = -1;
  412. }
  413. else { // getting the result failed
  414. return NULL;
  415. }
  416. }
  417. return pContext->BufferCache[TableIndex].Buffer;
  418. }
  419. //
  420. // Do a synch read for the buffer we need. We still need to make sure the previous read
  421. // has completed.
  422. //
  423. pBuffer = pContext->BufferCache[TableIndex].Buffer;
  424. Offset = FileOffset * BufferSize;
  425. if (pContext->BufferBeingRead != -1) {
  426. if (!GetOverlappedResult(hFile, &pContext->AsynchRead, &BytesTransffered, TRUE) &&
  427. GetLastError() != ERROR_HANDLE_EOF) {
  428. WmipDebugPrint(("GetOverlappedResult failed with Status %d in GetCurrentBuffer\n", GetLastError()));
  429. // cannot determine the status of the previous read
  430. return NULL;
  431. }
  432. }
  433. pContext->AsynchRead.Offset = (DWORD)(Offset & 0xFFFFFFFF);
  434. pContext->AsynchRead.OffsetHigh = (DWORD)(Offset >> 32);
  435. Status = WmipSynchReadFile(hFile,
  436. (LPVOID)pBuffer,
  437. BufferSize,
  438. &nBytesRead,
  439. &pContext->AsynchRead);
  440. pContext->BufferBeingRead = -1;
  441. if (nBytesRead == 0) {
  442. return NULL;
  443. }
  444. //
  445. // Update the cache entry with the one just read in
  446. //
  447. pContext->BufferCache[TableIndex].Index = FileOffset;
  448. //
  449. // We need to account for event alignments when backtracking to get the MofPtr.
  450. // (BufferOffset - EventSize) backtracks to the start of the current event.
  451. // Add EventHeaderSize and Subtract the MofLength gives the MofPtr.
  452. //
  453. if (pContext->ConversionFlags & EVENT_TRACE_GET_RAWEVENT) {
  454. Current->Event.MofData = ((PUCHAR)pBuffer
  455. + Current->BufferOffset
  456. - Current->EventSize);
  457. if (pContext->UsePerfClock == EVENT_TRACE_CLOCK_PERFCOUNTER) {
  458. //
  459. // Need to override the timestamp with SystemTime
  460. //
  461. switch(Current->TraceType) {
  462. case TRACE_HEADER_TYPE_PERFINFO32:
  463. case TRACE_HEADER_TYPE_PERFINFO64:
  464. {
  465. PPERFINFO_TRACE_HEADER pPerf = (PPERFINFO_TRACE_HEADER)Current->Event.MofData;
  466. pPerf->SystemTime = Current->Event.Header.TimeStamp;
  467. break;
  468. }
  469. case TRACE_HEADER_TYPE_SYSTEM32:
  470. {
  471. PSYSTEM_TRACE_HEADER pSystemHeader32 = (PSYSTEM_TRACE_HEADER) Current->Event.MofData;
  472. pSystemHeader32->SystemTime = Current->Event.Header.TimeStamp;
  473. break;
  474. }
  475. case TRACE_HEADER_TYPE_SYSTEM64:
  476. {
  477. PSYSTEM_TRACE_HEADER pSystemHeader64 = (PSYSTEM_TRACE_HEADER) Current->Event.MofData;
  478. pSystemHeader64->SystemTime = Current->Event.Header.TimeStamp;
  479. break;
  480. }
  481. case TRACE_HEADER_TYPE_FULL_HEADER:
  482. {
  483. PEVENT_TRACE_HEADER pWnodeHeader = (PEVENT_TRACE_HEADER) Current->Event.MofData;
  484. pWnodeHeader->TimeStamp = Current->Event.Header.TimeStamp;
  485. break;
  486. }
  487. case TRACE_HEADER_TYPE_INSTANCE:
  488. {
  489. PEVENT_INSTANCE_HEADER pInstanceHeader = (PEVENT_INSTANCE_HEADER) Current->Event.MofData;
  490. pInstanceHeader->TimeStamp = Current->Event.Header.TimeStamp;
  491. break;
  492. }
  493. case TRACE_HEADER_TYPE_TIMED:
  494. {
  495. PTIMED_TRACE_HEADER pTimedHeader = (PTIMED_TRACE_HEADER) Current->Event.MofData;
  496. pTimedHeader->TimeStamp = Current->Event.Header.TimeStamp;
  497. break;
  498. }
  499. case TRACE_HEADER_TYPE_WNODE_HEADER:
  500. case TRACE_HEADER_TYPE_MESSAGE:
  501. {
  502. break;
  503. }
  504. }
  505. }
  506. }
  507. else {
  508. //
  509. // When The FileOffset is 0 (First Buffer) and the EventType is
  510. // LOGFILE_HEADER
  511. //
  512. if ( (FileOffset == 0) &&
  513. ((Current->BufferOffset - Current->EventSize) == sizeof(WMI_BUFFER_HEADER)) )
  514. {
  515. Current->Event.MofData = (PVOID)&pContext->Logfile.LogfileHeader;
  516. }
  517. else
  518. {
  519. Current->Event.MofData = ((PUCHAR)pBuffer
  520. + Current->BufferOffset
  521. - Current->EventSize
  522. + Current->Event.Header.Size
  523. - Current->Event.MofLength );
  524. }
  525. }
  526. return pBuffer;
  527. }
  528. PTRACELOG_CONTEXT
  529. WmipAllocateTraceHandle()
  530. {
  531. PLIST_ENTRY Next, Head;
  532. PTRACELOG_CONTEXT NewHandleEntry, pEntry;
  533. WmipEnterPMCritSection();
  534. if (TraceHandleListHeadPtr == NULL) {
  535. TraceHandleListHeadPtr = WmipAlloc(sizeof(LIST_ENTRY));
  536. if (TraceHandleListHeadPtr == NULL) {
  537. WmipSetDosError(ERROR_OUTOFMEMORY);
  538. WmipLeavePMCritSection();
  539. return NULL;
  540. }
  541. InitializeListHead(TraceHandleListHeadPtr);
  542. }
  543. NewHandleEntry = WmipAlloc(sizeof(TRACELOG_CONTEXT));
  544. if (NewHandleEntry == NULL) {
  545. WmipSetDosError(ERROR_OUTOFMEMORY);
  546. WmipLeavePMCritSection();
  547. return NULL;
  548. }
  549. RtlZeroMemory(NewHandleEntry, sizeof(TRACELOG_CONTEXT));
  550. // AsynchRead initialization
  551. NewHandleEntry->BufferBeingRead = -1;
  552. NewHandleEntry->AsynchRead.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
  553. if (NewHandleEntry->AsynchRead.hEvent == NULL) {
  554. WmipFree(NewHandleEntry);
  555. WmipLeavePMCritSection();
  556. return NULL;
  557. }
  558. InitializeListHead(&NewHandleEntry->GuidMapListHead);
  559. Head = TraceHandleListHeadPtr;
  560. Next = Head->Flink;
  561. if (Next == Head) {
  562. NewHandleEntry->TraceHandle = 1;
  563. InsertTailList(Head, &NewHandleEntry->Entry);
  564. WmipLeavePMCritSection();
  565. return NewHandleEntry;
  566. }
  567. while (Next != Head) {
  568. pEntry = CONTAINING_RECORD( Next, TRACELOG_CONTEXT, Entry );
  569. Next = Next->Flink;
  570. NewHandleEntry->TraceHandle++;
  571. if (NewHandleEntry->TraceHandle < pEntry->TraceHandle) {
  572. InsertTailList(&pEntry->Entry, &NewHandleEntry->Entry);
  573. WmipLeavePMCritSection();
  574. return NewHandleEntry;
  575. }
  576. }
  577. //
  578. // TODO: Need to optimize this case out first before searching...
  579. //
  580. NewHandleEntry->TraceHandle++;
  581. InsertTailList(Head, &NewHandleEntry->Entry);
  582. WmipLeavePMCritSection();
  583. return NewHandleEntry;
  584. }
  585. PTRACELOG_CONTEXT
  586. WmipLookupTraceHandle(
  587. TRACEHANDLE TraceHandle
  588. )
  589. {
  590. PLIST_ENTRY Head, Next;
  591. PTRACELOG_CONTEXT pEntry;
  592. WmipEnterPMCritSection();
  593. Head = TraceHandleListHeadPtr;
  594. if (Head == NULL) {
  595. WmipLeavePMCritSection();
  596. return NULL;
  597. }
  598. Next = Head->Flink;
  599. while (Next != Head) {
  600. pEntry = CONTAINING_RECORD( Next, TRACELOG_CONTEXT, Entry );
  601. Next = Next->Flink;
  602. if (TraceHandle == pEntry->TraceHandle) {
  603. WmipLeavePMCritSection();
  604. return pEntry;
  605. }
  606. }
  607. WmipLeavePMCritSection();
  608. return NULL;
  609. }
  610. ULONG
  611. WmipFreeTraceHandle(
  612. TRACEHANDLE TraceHandle
  613. )
  614. {
  615. PLIST_ENTRY Head, Next;
  616. PTRACELOG_CONTEXT pEntry;
  617. WmipEnterPMCritSection();
  618. Head = TraceHandleListHeadPtr;
  619. if (Head == NULL) {
  620. WmipLeavePMCritSection();
  621. return ERROR_INVALID_HANDLE;
  622. }
  623. Next = Head->Flink;
  624. while (Next != Head) {
  625. pEntry = CONTAINING_RECORD( Next, TRACELOG_CONTEXT, Entry );
  626. Next = Next->Flink;
  627. if (TraceHandle == pEntry->TraceHandle) {
  628. if (pEntry->fProcessed == TRUE)
  629. {
  630. WmipLeavePMCritSection();
  631. return ERROR_BUSY;
  632. }
  633. RemoveEntryList(&pEntry->Entry);
  634. // Free pEntry memory
  635. //
  636. if (pEntry->Logfile.LogFileName != NULL)
  637. {
  638. WmipFree(pEntry->Logfile.LogFileName);
  639. }
  640. if (pEntry->Logfile.LoggerName != NULL)
  641. {
  642. WmipFree(pEntry->Logfile.LoggerName);
  643. }
  644. CloseHandle(pEntry->AsynchRead.hEvent);
  645. WmipFree(pEntry);
  646. //
  647. // If the handle list is empty, then delete it.
  648. //
  649. if (Head == Head->Flink) {
  650. WmipFree(TraceHandleListHeadPtr);
  651. TraceHandleListHeadPtr = NULL;
  652. }
  653. WmipLeavePMCritSection();
  654. return ERROR_SUCCESS;
  655. }
  656. }
  657. WmipLeavePMCritSection();
  658. return ERROR_INVALID_HANDLE;
  659. }
  660. ULONG
  661. WMIAPI
  662. WmipCreateGuidMapping(void)
  663. /*++
  664. Routine Description:
  665. This routine is used to create the mapping array between GroupTypes and Guid
  666. for kernel events.
  667. Arguments:
  668. None.
  669. Returned Value:
  670. None
  671. --*/
  672. {
  673. ULONG i = 0;
  674. ULONG listsize;
  675. if (EventMapList == NULL) {
  676. listsize = sizeof(TRACE_GUID_MAP) * MAX_KERNEL_TRACE_EVENTS;
  677. EventMapList = (PTRACE_GUID_MAP) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, listsize);
  678. if (EventMapList == NULL) {
  679. return WmipSetDosError(ERROR_OUTOFMEMORY);
  680. }
  681. EventMapList[i].GroupType = EVENT_TRACE_GROUP_IO;
  682. RtlCopyMemory(&EventMapList[i++].Guid,&DiskIoGuid, sizeof(GUID));
  683. EventMapList[i].GroupType = EVENT_TRACE_GROUP_FILE;
  684. RtlCopyMemory(&EventMapList[i++].Guid, &FileIoGuid, sizeof(GUID));
  685. EventMapList[i].GroupType = EVENT_TRACE_GROUP_TCPIP;
  686. RtlCopyMemory(&EventMapList[i++].Guid, &TcpIpGuid, sizeof(GUID));
  687. EventMapList[i].GroupType = EVENT_TRACE_GROUP_UDPIP;
  688. RtlCopyMemory(&EventMapList[i++].Guid, &UdpIpGuid, sizeof(GUID));
  689. EventMapList[i].GroupType = EVENT_TRACE_GROUP_THREAD;
  690. RtlCopyMemory(&EventMapList[i++].Guid, &ThreadGuid, sizeof(GUID));
  691. EventMapList[i].GroupType = EVENT_TRACE_GROUP_PROCESS;
  692. RtlCopyMemory(&EventMapList[i++].Guid, &ProcessGuid, sizeof(GUID));
  693. EventMapList[i].GroupType = EVENT_TRACE_GROUP_MEMORY;
  694. RtlCopyMemory(&EventMapList[i++].Guid, &PageFaultGuid, sizeof(GUID));
  695. EventMapList[i].GroupType = EVENT_TRACE_GROUP_HEADER;
  696. RtlCopyMemory(&EventMapList[i++].Guid, &EventTraceGuid, sizeof(GUID));
  697. EventMapList[i].GroupType = EVENT_TRACE_GROUP_PROCESS +
  698. EVENT_TRACE_TYPE_LOAD;
  699. RtlCopyMemory(&EventMapList[i++].Guid, &ImageLoadGuid, sizeof(GUID));
  700. EventMapList[i].GroupType = EVENT_TRACE_GROUP_REGISTRY;
  701. RtlCopyMemory(&EventMapList[i++].Guid, &RegistryGuid, sizeof(GUID));
  702. EventMapList[i].GroupType = EVENT_TRACE_GROUP_DBGPRINT;
  703. RtlCopyMemory(&EventMapList[i++].Guid, &DbgPrintGuid, sizeof(GUID));
  704. EventMapList[i].GroupType = EVENT_TRACE_GROUP_CONFIG;
  705. RtlCopyMemory(&EventMapList[i++].Guid, &EventTraceConfigGuid, sizeof(GUID));
  706. EventMapList[i].GroupType = EVENT_TRACE_GROUP_POOL;
  707. RtlCopyMemory(&EventMapList[i++].Guid, &PoolGuid, sizeof(GUID));
  708. EventMapList[i].GroupType = EVENT_TRACE_GROUP_PERFINFO;
  709. RtlCopyMemory(&EventMapList[i++].Guid, &PerfinfoGuid, sizeof(GUID));
  710. EventMapList[i].GroupType = EVENT_TRACE_GROUP_HEAP;
  711. RtlCopyMemory(&EventMapList[i++].Guid, &HeapGuid, sizeof(GUID));
  712. EventMapList[i].GroupType = EVENT_TRACE_GROUP_OBJECT;
  713. RtlCopyMemory(&EventMapList[i++].Guid, &ObjectGuid, sizeof(GUID));
  714. EventMapList[i].GroupType = EVENT_TRACE_GROUP_MODBOUND;
  715. RtlCopyMemory(&EventMapList[i++].Guid, &ModBoundGuid, sizeof(GUID));
  716. EventMapList[i].GroupType = EVENT_TRACE_GROUP_DPC;
  717. RtlCopyMemory(&EventMapList[i++].Guid, &DpcGuid, sizeof(GUID));
  718. EventMapList[i].GroupType = EVENT_TRACE_GROUP_POWER;
  719. RtlCopyMemory(&EventMapList[i++].Guid, &PowerGuid, sizeof(GUID));
  720. EventMapList[i].GroupType = EVENT_TRACE_GROUP_CRITSEC;
  721. RtlCopyMemory(&EventMapList[i++].Guid, &CritSecGuid, sizeof(GUID));
  722. }
  723. return WmipSetDosError(ERROR_SUCCESS);
  724. }
  725. LPGUID
  726. WmipGuidMapHandleToGuid(
  727. PLIST_ENTRY GuidMapListHeadPtr,
  728. ULONGLONG GuidHandle
  729. )
  730. {
  731. PLIST_ENTRY Next, Head;
  732. PEVENT_GUID_MAP GuidMap;
  733. ULONG retry_count=0;
  734. retry:
  735. WmipEnterPMCritSection();
  736. Head = GuidMapListHeadPtr;
  737. Next = Head->Flink;
  738. while (Next != Head) {
  739. GuidMap = CONTAINING_RECORD( Next, EVENT_GUID_MAP, Entry );
  740. if (GuidMap->GuidHandle == GuidHandle) {
  741. WmipLeavePMCritSection();
  742. return (&GuidMap->Guid);
  743. }
  744. Next = Next->Flink;
  745. }
  746. WmipLeavePMCritSection();
  747. //
  748. // At this point, assume that this is realtime feed and
  749. // and try to dumpout guids and try again.
  750. if ((WmipDumpGuidMaps(NULL, GuidMapListHeadPtr, TRUE) > 0) &&
  751. (retry_count++ < 1)) {
  752. goto retry;
  753. }
  754. return NULL;
  755. }
  756. ULONG
  757. WmipAddGuidHandleToGuidMapList(
  758. IN PLIST_ENTRY GuidMapListHeadPtr,
  759. IN ULONGLONG GuidHandle,
  760. IN LPGUID Guid
  761. )
  762. {
  763. PEVENT_GUID_MAP GuidMap;
  764. if (GuidMapListHeadPtr != NULL) {
  765. GuidMap = WmipAlloc(sizeof(EVENT_GUID_MAP));
  766. if (GuidMap == NULL)
  767. return WmipSetDosError(ERROR_OUTOFMEMORY);
  768. RtlZeroMemory(GuidMap, sizeof(EVENT_GUID_MAP));
  769. GuidMap->GuidHandle = GuidHandle;
  770. GuidMap->Guid = *Guid;
  771. WmipEnterPMCritSection();
  772. InsertTailList(GuidMapListHeadPtr, &GuidMap->Entry);
  773. WmipLeavePMCritSection();
  774. }
  775. return WmipSetDosError(ERROR_SUCCESS);
  776. }
  777. void
  778. WmipCleanupGuidMapList(
  779. PLIST_ENTRY GuidMapListHeadPtr
  780. )
  781. {
  782. PLIST_ENTRY Next, Head;
  783. PEVENT_GUID_MAP GuidMap;
  784. WmipEnterPMCritSection();
  785. if (GuidMapListHeadPtr != NULL) {
  786. Head = GuidMapListHeadPtr;
  787. Next = Head->Flink;
  788. while (Next != Head) {
  789. GuidMap = CONTAINING_RECORD( Next, EVENT_GUID_MAP, Entry );
  790. Next = Next->Flink;
  791. RemoveEntryList(&GuidMap->Entry);
  792. WmipFree(GuidMap);
  793. }
  794. GuidMapListHeadPtr = NULL;
  795. }
  796. WmipLeavePMCritSection();
  797. }
  798. LPGUID
  799. WmipGroupTypeToGuid(
  800. ULONG GroupType
  801. )
  802. /*++
  803. Routine Description:
  804. This routine returns the GUID corresponding to a given GroupType.
  805. The mapping is static and is defined by the kernel provider.
  806. Arguments:
  807. GroupType The GroupType of the kernel event.
  808. Returned Value:
  809. Pointer to the GUID representing the given GroupType.
  810. --*/
  811. {
  812. ULONG i;
  813. for (i = 0; i < MAX_KERNEL_TRACE_EVENTS; i++) {
  814. if (EventMapList[i].GroupType == GroupType)
  815. return (&EventMapList[i].Guid);
  816. }
  817. return NULL;
  818. }
  819. VOID
  820. WmipFreeCallbackList()
  821. /*++
  822. Routine Description:
  823. This routine removes all event callbacks and frees the storage.
  824. Arguments:
  825. None
  826. Returned Value:
  827. None.
  828. --*/
  829. {
  830. PLIST_ENTRY Next, Head;
  831. PEVENT_TRACE_CALLBACK EventCb;
  832. if (EventCallbackListHead == NULL)
  833. return;
  834. WmipEnterPMCritSection();
  835. Head = EventCallbackListHead;
  836. Next = Head->Flink;
  837. while (Next != Head) {
  838. EventCb = CONTAINING_RECORD( Next, EVENT_TRACE_CALLBACK, Entry );
  839. Next = Next->Flink;
  840. RemoveEntryList(&EventCb->Entry);
  841. WmipFree(EventCb);
  842. }
  843. WmipFree(EventCallbackListHead);
  844. EventCallbackListHead = NULL;
  845. WmipLeavePMCritSection();
  846. }
  847. PEVENT_TRACE_CALLBACK
  848. WmipGetCallbackRoutine(
  849. LPGUID pGuid
  850. )
  851. /*++
  852. Routine Description:
  853. This routine returns the callback function for a given Guid.
  854. If no callback was registered for the Guid, returns NULL.
  855. Arguments:
  856. pGuid pointer to the Guid.
  857. Returned Value:
  858. Event Trace Callback Function.
  859. --*/
  860. {
  861. PLIST_ENTRY head, next;
  862. PEVENT_TRACE_CALLBACK pEventCb = NULL;
  863. if (pGuid == NULL)
  864. return NULL;
  865. WmipEnterPMCritSection();
  866. if (EventCallbackListHead == NULL) {
  867. WmipLeavePMCritSection();
  868. return NULL;
  869. }
  870. head = EventCallbackListHead;
  871. next = head->Flink;
  872. while (next != head) {
  873. pEventCb = CONTAINING_RECORD( next, EVENT_TRACE_CALLBACK, Entry);
  874. if (IsEqualGUID(pGuid, &pEventCb->Guid)) {
  875. WmipLeavePMCritSection();
  876. return (pEventCb);
  877. }
  878. next = next->Flink;
  879. }
  880. WmipLeavePMCritSection();
  881. return NULL;
  882. }
  883. ULONG
  884. WMIAPI
  885. SetTraceCallback(
  886. IN LPCGUID pGuid,
  887. IN PEVENT_CALLBACK EventCallback
  888. )
  889. /*++
  890. Routine Description:
  891. This routine is used to wire a callback function for Guid. The
  892. callback function is called when an Event with this Guid is found in
  893. the subsequent ProcessTraceLog Call.
  894. Arguments:
  895. pGuid Pointer to the Guid.
  896. func Callback Function Address.
  897. Return Value:
  898. ERROR_SUCCESS Callback function is wired
  899. --*/
  900. {
  901. PEVENT_TRACE_CALLBACK pEventCb;
  902. PLIST_ENTRY head, next;
  903. GUID FilterGuid;
  904. ULONG Checksum;
  905. ULONG Status;
  906. WmipInitProcessHeap();
  907. if ((pGuid == NULL) || (EventCallback == NULL) ||
  908. (EventCallback == (PEVENT_CALLBACK) -1 ) ) {
  909. return WmipSetDosError(ERROR_INVALID_PARAMETER);
  910. }
  911. //
  912. // Capture the Guid first
  913. //
  914. try {
  915. FilterGuid = *pGuid;
  916. Checksum = *((PULONG)EventCallback);
  917. if (Checksum) {
  918. Status = Checksum;
  919. }
  920. }
  921. except (EXCEPTION_EXECUTE_HANDLER) {
  922. return WmipSetDosError(ERROR_NOACCESS);
  923. }
  924. WmipEnterPMCritSection();
  925. if (EventCallbackListHead == NULL) {
  926. EventCallbackListHead = (PLIST_ENTRY) WmipAlloc(sizeof(LIST_ENTRY));
  927. if (EventCallbackListHead == NULL) {
  928. WmipLeavePMCritSection();
  929. return WmipSetDosError(ERROR_OUTOFMEMORY);
  930. }
  931. InitializeListHead(EventCallbackListHead);
  932. }
  933. //
  934. // If there is a callback wired for this Guid, simply update the function.
  935. //
  936. head = EventCallbackListHead;
  937. next = head->Flink;
  938. while (next != head) {
  939. pEventCb = CONTAINING_RECORD( next, EVENT_TRACE_CALLBACK, Entry);
  940. if (IsEqualGUID(&FilterGuid, &pEventCb->Guid)) {
  941. pEventCb->CallbackRoutine = EventCallback;
  942. WmipLeavePMCritSection();
  943. return WmipSetDosError(ERROR_SUCCESS);
  944. }
  945. next = next->Flink;
  946. }
  947. //
  948. // Create a new entry in the EventCallbackList for this Guid.
  949. //
  950. pEventCb = (PEVENT_TRACE_CALLBACK) WmipAlloc (sizeof(EVENT_TRACE_CALLBACK));
  951. if (pEventCb == NULL) {
  952. WmipLeavePMCritSection();
  953. return WmipSetDosError(ERROR_OUTOFMEMORY);
  954. }
  955. RtlZeroMemory(pEventCb, sizeof(EVENT_TRACE_CALLBACK));
  956. pEventCb->Guid = FilterGuid;
  957. pEventCb->CallbackRoutine = EventCallback;
  958. InsertTailList(EventCallbackListHead, &pEventCb->Entry);
  959. WmipLeavePMCritSection();
  960. Status = ERROR_SUCCESS;
  961. return WmipSetDosError(Status);
  962. }
  963. ULONG
  964. WMIAPI
  965. RemoveTraceCallback(
  966. IN LPCGUID pGuid
  967. )
  968. /*++
  969. Routine Description:
  970. This routine removes a callback function for a given Guid.
  971. Arguments:
  972. pGuid Pointer to the Guid for which the callback routine needs
  973. to be deleted.
  974. Return Value:
  975. ERROR_SUCCESS Successfully deleted the callback routine.
  976. ERROR_INVALID_PARAMETER Could not find any callbacks for the Guid.
  977. --*/
  978. {
  979. PLIST_ENTRY next, head;
  980. PEVENT_TRACE_CALLBACK EventCb;
  981. GUID RemoveGuid;
  982. ULONG errorCode;
  983. #ifdef DBG
  984. CHAR GuidStr[64];
  985. #endif
  986. WmipInitProcessHeap();
  987. if ((pGuid == NULL) || (EventCallbackListHead == NULL))
  988. return WmipSetDosError(ERROR_INVALID_PARAMETER);
  989. //
  990. // Capture the Guid into a local variable first
  991. //
  992. try {
  993. RemoveGuid = *pGuid;
  994. }
  995. except (EXCEPTION_EXECUTE_HANDLER) {
  996. return WmipSetDosError(ERROR_NOACCESS);
  997. }
  998. errorCode = ERROR_WMI_GUID_NOT_FOUND;
  999. WmipEnterPMCritSection();
  1000. head = EventCallbackListHead;
  1001. next = head->Flink;
  1002. while (next != head) {
  1003. EventCb = CONTAINING_RECORD( next, EVENT_TRACE_CALLBACK, Entry);
  1004. next = next->Flink;
  1005. if (IsEqualGUID(&EventCb->Guid, &RemoveGuid)) {
  1006. RemoveEntryList(&EventCb->Entry);
  1007. WmipFree(EventCb);
  1008. errorCode = ERROR_SUCCESS;
  1009. }
  1010. }
  1011. WmipLeavePMCritSection();
  1012. return WmipSetDosError(errorCode);
  1013. }
  1014. #ifdef DBG
  1015. void
  1016. WmipDumpEvent(
  1017. PEVENT_TRACE pEvent
  1018. )
  1019. {
  1020. DbgPrint("\tSize %d\n", pEvent->Header.Size);
  1021. DbgPrint("\tThreadId %X\n", pEvent->Header.ThreadId);
  1022. DbgPrint("\tTime Stamp %I64u\n", pEvent->Header.TimeStamp.QuadPart);
  1023. }
  1024. void
  1025. WmipDumpGuid(
  1026. LPGUID pGuid
  1027. )
  1028. {
  1029. DbgPrint("Guid=%x,%x,%x,\n\t{%x,%x,%x,%x,%x,%x,%x}\n",
  1030. pGuid->Data1, pGuid->Data2, pGuid->Data3,
  1031. pGuid->Data4[0], pGuid->Data4[1], pGuid->Data4[2], pGuid->Data4[3],
  1032. pGuid->Data4[5], pGuid->Data4[6], pGuid->Data4[7], pGuid->Data4[8]);
  1033. }
  1034. void WmipDumpCallbacks()
  1035. {
  1036. PLIST_ENTRY next, head;
  1037. PEVENT_TRACE_CALLBACK EventCb;
  1038. if (EventCallbackListHead == NULL)
  1039. return;
  1040. WmipEnterPMCritSection();
  1041. head = EventCallbackListHead;
  1042. next = head->Flink;
  1043. while (next != head) {
  1044. EventCb = CONTAINING_RECORD(next, EVENT_TRACE_CALLBACK, Entry);
  1045. WmipDumpGuid(&EventCb->Guid);
  1046. next = next->Flink;
  1047. }
  1048. WmipLeavePMCritSection();
  1049. }
  1050. #endif
  1051. VOID
  1052. WmipCalculateCurrentTime (
  1053. OUT PLARGE_INTEGER DestTime,
  1054. IN PLARGE_INTEGER TimeValue,
  1055. IN PTRACELOG_CONTEXT pContext
  1056. )
  1057. {
  1058. ULONG64 StartPerfClock;
  1059. ULONG64 CurrentTime, TimeStamp;
  1060. ULONG64 Delta;
  1061. double dDelta;
  1062. if (pContext == NULL) {
  1063. Move64(TimeValue, DestTime);
  1064. return;
  1065. }
  1066. if (pContext->ConversionFlags & EVENT_TRACE_GET_RAWEVENT) {
  1067. Move64(TimeValue, DestTime);
  1068. return;
  1069. }
  1070. Move64(TimeValue, (PLARGE_INTEGER) &TimeStamp);
  1071. if ((pContext->UsePerfClock == EVENT_TRACE_CLOCK_SYSTEMTIME) ||
  1072. (pContext->UsePerfClock == EVENT_TRACE_CLOCK_RAW)) {
  1073. //
  1074. // System time, just return the time stamp.
  1075. //
  1076. Move64(TimeValue, DestTime);
  1077. return;
  1078. }
  1079. else if (pContext->UsePerfClock == EVENT_TRACE_CLOCK_PERFCOUNTER) {
  1080. if (pContext->PerfFreq.QuadPart == 0) {
  1081. Move64(TimeValue, DestTime);
  1082. return;
  1083. }
  1084. StartPerfClock = pContext->StartPerfClock.QuadPart;
  1085. if (TimeStamp > StartPerfClock) {
  1086. Delta = (TimeStamp - StartPerfClock);
  1087. dDelta = ((double) Delta) * (10000000.0 / (double)pContext->PerfFreq.QuadPart);
  1088. Delta = (ULONG64)dDelta;
  1089. CurrentTime = pContext->StartTime.QuadPart + Delta;
  1090. }
  1091. else {
  1092. Delta = StartPerfClock - TimeStamp;
  1093. dDelta = ((double) Delta) * (10000000.0 / (double)pContext->PerfFreq.QuadPart);
  1094. Delta = (ULONG64)dDelta;
  1095. CurrentTime = pContext->StartTime.QuadPart - Delta;
  1096. }
  1097. Move64((PLARGE_INTEGER) &CurrentTime, DestTime);
  1098. return;
  1099. }
  1100. else {
  1101. if (pContext->CpuSpeedInMHz == 0) {
  1102. Move64(TimeValue, DestTime);
  1103. return;
  1104. }
  1105. StartPerfClock = pContext->StartPerfClock.QuadPart;
  1106. if (TimeStamp > StartPerfClock) {
  1107. Delta = (TimeStamp - StartPerfClock);
  1108. dDelta = ((double) Delta) * (10.0 / (double)pContext->CpuSpeedInMHz);
  1109. Delta = (ULONG64)dDelta;
  1110. CurrentTime = pContext->StartTime.QuadPart + Delta;
  1111. }
  1112. else {
  1113. Delta = StartPerfClock - TimeStamp;
  1114. dDelta = ((double) Delta) * (10.0 / (double)pContext->CpuSpeedInMHz);
  1115. Delta = (ULONG64)dDelta;
  1116. CurrentTime = pContext->StartTime.QuadPart - Delta;
  1117. }
  1118. Move64((PLARGE_INTEGER) &CurrentTime, DestTime);
  1119. return;
  1120. }
  1121. }
  1122. ULONG
  1123. WmipCopyCurrentEvent(
  1124. PTRACELOG_CONTEXT pContext,
  1125. PVOID pHeader,
  1126. PEVENT_TRACE pEvent,
  1127. ULONG TraceType,
  1128. PWMI_BUFFER_HEADER LogBuffer
  1129. )
  1130. /*++
  1131. Routine Description:
  1132. This routine copies the Current Event from the logfile buffer stream to
  1133. the CurrentEvent structure provided by the caller. The routine takes
  1134. care of the differences between kernel event and user events by mapping
  1135. all events uniformly to the EVENT_TRACE_HEADER structure.
  1136. Arguments:
  1137. pHeader Pointer to the datablock in the input stream (logfile).
  1138. pEvent Current Event to which the data is copied.
  1139. TraceType Enum indicating the header type.
  1140. LogBuffer The buffer
  1141. Returned Value:
  1142. Status indicating success or failure.
  1143. --*/
  1144. {
  1145. PEVENT_TRACE_HEADER pWnode;
  1146. PEVENT_TRACE_HEADER pWnodeHeader;
  1147. ULONG nGroupType;
  1148. LPGUID pGuid;
  1149. ULONG UsePerfClock = 0;
  1150. ULONG UseBasePtr = 0;
  1151. ULONG PrivateLogger=0;
  1152. if (pHeader == NULL || pEvent == NULL)
  1153. return WmipSetDosError(ERROR_INVALID_PARAMETER);
  1154. if (pContext != NULL) {
  1155. UsePerfClock = pContext->UsePerfClock;
  1156. UseBasePtr = pContext->ConversionFlags & EVENT_TRACE_GET_RAWEVENT;
  1157. PrivateLogger = (pContext->Logfile.LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE);
  1158. }
  1159. switch(TraceType) {
  1160. //
  1161. // ISSUE: Need to split the two so we can process cross platform.
  1162. // shsiao 03/22/2000
  1163. //
  1164. case TRACE_HEADER_TYPE_PERFINFO32:
  1165. case TRACE_HEADER_TYPE_PERFINFO64:
  1166. {
  1167. PPERFINFO_TRACE_HEADER pPerfHeader;
  1168. pPerfHeader = (PPERFINFO_TRACE_HEADER) pHeader;
  1169. nGroupType = pPerfHeader->Packet.Group << 8;
  1170. if ((nGroupType == EVENT_TRACE_GROUP_PROCESS) &&
  1171. (pPerfHeader->Packet.Type == EVENT_TRACE_TYPE_LOAD)) {
  1172. nGroupType += pPerfHeader->Packet.Type;
  1173. }
  1174. RtlZeroMemory(pEvent, sizeof(EVENT_TRACE));
  1175. pWnode = (PEVENT_TRACE_HEADER) &pEvent->Header;
  1176. pGuid = WmipGroupTypeToGuid(nGroupType);
  1177. if (pGuid != NULL)
  1178. RtlCopyMemory(&pWnode->Guid, pGuid, sizeof(GUID));
  1179. pWnode->Size = pPerfHeader->Packet.Size;
  1180. pWnode->Class.Type = pPerfHeader->Packet.Type;
  1181. pWnode->Class.Version = pPerfHeader->Version;
  1182. WmipCalculateCurrentTime( &pWnode->TimeStamp,
  1183. &pPerfHeader->SystemTime,
  1184. pContext );
  1185. //
  1186. // PERFINFO headers does not have ThreadId or CPU Times
  1187. //
  1188. if( LogBuffer->Flags & WNODE_FLAG_THREAD_BUFFER ){
  1189. pWnode->ThreadId = LogBuffer->CurrentOffset;
  1190. } else {
  1191. pWnode->ProcessId = -1;
  1192. pWnode->ThreadId = -1;
  1193. }
  1194. if (UseBasePtr) {
  1195. pEvent->MofData = (PVOID) pHeader;
  1196. pEvent->MofLength = pWnode->Size;
  1197. //
  1198. // Override the Timestamp with SystemTime from PERFCounter.
  1199. // If rdtsc is used no conversion is done.
  1200. //
  1201. if (UsePerfClock == EVENT_TRACE_CLOCK_PERFCOUNTER) {
  1202. pPerfHeader->SystemTime = pWnode->TimeStamp;
  1203. }
  1204. }
  1205. else if (pWnode->Size > FIELD_OFFSET(PERFINFO_TRACE_HEADER, Data)) {
  1206. pEvent->MofData = (PVOID) ((char*) pHeader +
  1207. FIELD_OFFSET(PERFINFO_TRACE_HEADER, Data));
  1208. pEvent->MofLength = pWnode->Size - FIELD_OFFSET(PERFINFO_TRACE_HEADER, Data);
  1209. }
  1210. pEvent->Header.FieldTypeFlags = EVENT_TRACE_USE_NOCPUTIME;
  1211. break;
  1212. }
  1213. case TRACE_HEADER_TYPE_SYSTEM32:
  1214. {
  1215. PSYSTEM_TRACE_HEADER pSystemHeader32;
  1216. pSystemHeader32 = (PSYSTEM_TRACE_HEADER) pHeader;
  1217. nGroupType = pSystemHeader32->Packet.Group << 8;
  1218. if ((nGroupType == EVENT_TRACE_GROUP_PROCESS) &&
  1219. (pSystemHeader32->Packet.Type == EVENT_TRACE_TYPE_LOAD)) {
  1220. nGroupType += pSystemHeader32->Packet.Type;
  1221. }
  1222. RtlZeroMemory(pEvent, sizeof(EVENT_TRACE));
  1223. pWnode = (PEVENT_TRACE_HEADER) &pEvent->Header;
  1224. pGuid = WmipGroupTypeToGuid(nGroupType);
  1225. if (pGuid != NULL)
  1226. RtlCopyMemory(&pWnode->Guid, pGuid, sizeof(GUID));
  1227. pWnode->Size = pSystemHeader32->Packet.Size;
  1228. pWnode->ThreadId = pSystemHeader32->ThreadId;
  1229. pWnode->ProcessId = pSystemHeader32->ProcessId;
  1230. pWnode->KernelTime = pSystemHeader32->KernelTime;
  1231. pWnode->UserTime = pSystemHeader32->UserTime;
  1232. pWnode->Class.Type = pSystemHeader32->Packet.Type;
  1233. pWnode->Class.Version = pSystemHeader32->Version;
  1234. WmipCalculateCurrentTime( &pWnode->TimeStamp,
  1235. &pSystemHeader32->SystemTime,
  1236. pContext );
  1237. if (UseBasePtr) {
  1238. pEvent->MofData = (PVOID) pHeader;
  1239. pEvent->MofLength = pWnode->Size;
  1240. if (UsePerfClock == EVENT_TRACE_CLOCK_PERFCOUNTER) {
  1241. pSystemHeader32->SystemTime = pWnode->TimeStamp;
  1242. }
  1243. }
  1244. else {
  1245. pWnode->FieldTypeFlags = 0;
  1246. if (pWnode->Size > sizeof(SYSTEM_TRACE_HEADER)) {
  1247. pEvent->MofData = (PVOID) ((char*) pHeader +
  1248. sizeof(SYSTEM_TRACE_HEADER));
  1249. pEvent->MofLength = pWnode->Size - sizeof(SYSTEM_TRACE_HEADER);
  1250. }
  1251. }
  1252. break;
  1253. }
  1254. case TRACE_HEADER_TYPE_SYSTEM64:
  1255. {
  1256. PSYSTEM_TRACE_HEADER pSystemHeader64;
  1257. pSystemHeader64 = (PSYSTEM_TRACE_HEADER) pHeader;
  1258. nGroupType = pSystemHeader64->Packet.Group << 8;
  1259. if ((nGroupType == EVENT_TRACE_GROUP_PROCESS) &&
  1260. (pSystemHeader64->Packet.Type == EVENT_TRACE_TYPE_LOAD)) {
  1261. nGroupType += pSystemHeader64->Packet.Type;
  1262. }
  1263. RtlZeroMemory(pEvent, sizeof(EVENT_TRACE));
  1264. pWnode = (PEVENT_TRACE_HEADER) &pEvent->Header;
  1265. pGuid = WmipGroupTypeToGuid(nGroupType);
  1266. if (pGuid != NULL)
  1267. RtlCopyMemory(&pWnode->Guid, pGuid, sizeof(GUID));
  1268. pWnode->Size = pSystemHeader64->Packet.Size;
  1269. pWnode->ThreadId = pSystemHeader64->ThreadId;
  1270. pWnode->ProcessId = pSystemHeader64->ProcessId;
  1271. pWnode->KernelTime = pSystemHeader64->KernelTime;
  1272. pWnode->UserTime = pSystemHeader64->UserTime;
  1273. pWnode->Class.Type = pSystemHeader64->Packet.Type;
  1274. pWnode->Class.Version = pSystemHeader64->Version;
  1275. WmipCalculateCurrentTime( &pWnode->TimeStamp,
  1276. &pSystemHeader64->SystemTime,
  1277. pContext );
  1278. if (UseBasePtr) {
  1279. pEvent->MofData = (PVOID) pHeader;
  1280. pEvent->MofLength = pWnode->Size;
  1281. if (UsePerfClock == EVENT_TRACE_CLOCK_PERFCOUNTER) {
  1282. pSystemHeader64->SystemTime = pWnode->TimeStamp;
  1283. }
  1284. }
  1285. else {
  1286. pWnode->FieldTypeFlags = 0;
  1287. if (pWnode->Size > sizeof(SYSTEM_TRACE_HEADER)) {
  1288. pEvent->MofData = (PVOID) ((char*) pHeader +
  1289. sizeof(SYSTEM_TRACE_HEADER));
  1290. pEvent->MofLength = pWnode->Size - sizeof(SYSTEM_TRACE_HEADER);
  1291. }
  1292. }
  1293. break;
  1294. }
  1295. case TRACE_HEADER_TYPE_FULL_HEADER:
  1296. {
  1297. pWnodeHeader = (PEVENT_TRACE_HEADER) pHeader;
  1298. RtlZeroMemory(pEvent, sizeof(EVENT_TRACE));
  1299. pWnode = (PEVENT_TRACE_HEADER) &pEvent->Header;
  1300. RtlCopyMemory(pWnode,
  1301. pWnodeHeader,
  1302. sizeof(EVENT_TRACE_HEADER)
  1303. );
  1304. WmipCalculateCurrentTime( &pWnode->TimeStamp,
  1305. &pWnodeHeader->TimeStamp,
  1306. pContext );
  1307. if (UseBasePtr) {
  1308. pEvent->Header.Size = pWnodeHeader->Size;
  1309. pEvent->MofData = (PVOID)pHeader;
  1310. pEvent->MofLength = pWnodeHeader->Size;
  1311. if (UsePerfClock == EVENT_TRACE_CLOCK_PERFCOUNTER) {
  1312. pWnodeHeader->TimeStamp = pWnode->TimeStamp;
  1313. }
  1314. }
  1315. else {
  1316. //
  1317. // If the data came from Process Private Logger, then
  1318. // mark the ProcessorTime field as valid
  1319. //
  1320. pEvent->Header.FieldTypeFlags = (PrivateLogger) ? EVENT_TRACE_USE_PROCTIME : 0;
  1321. if (pWnodeHeader->Size > sizeof(EVENT_TRACE_HEADER)) {
  1322. pEvent->MofData = (PVOID) ((char*)pWnodeHeader +
  1323. sizeof(EVENT_TRACE_HEADER));
  1324. pEvent->MofLength = pWnodeHeader->Size -
  1325. sizeof(EVENT_TRACE_HEADER);
  1326. }
  1327. }
  1328. break;
  1329. }
  1330. case TRACE_HEADER_TYPE_INSTANCE:
  1331. {
  1332. PEVENT_INSTANCE_HEADER pInstanceHeader;
  1333. pInstanceHeader = (PEVENT_INSTANCE_HEADER) pHeader;
  1334. RtlZeroMemory(pEvent, sizeof(EVENT_TRACE));
  1335. pWnode = (PEVENT_TRACE_HEADER) &pEvent->Header;
  1336. RtlCopyMemory(pWnode,
  1337. pInstanceHeader,
  1338. sizeof(EVENT_INSTANCE_HEADER)
  1339. );
  1340. WmipCalculateCurrentTime( &pWnode->TimeStamp,
  1341. &pInstanceHeader->TimeStamp,
  1342. pContext );
  1343. pEvent->InstanceId = pInstanceHeader->InstanceId;
  1344. pEvent->ParentInstanceId = pInstanceHeader->ParentInstanceId;
  1345. pGuid = WmipGuidMapHandleToGuid(&pContext->GuidMapListHead, pInstanceHeader->RegHandle);
  1346. if (pGuid != NULL) {
  1347. pEvent->Header.Guid = *pGuid;
  1348. }
  1349. else {
  1350. RtlZeroMemory(&pEvent->Header.Guid, sizeof(GUID));
  1351. }
  1352. if (pInstanceHeader->ParentRegHandle != (ULONGLONG)0) {
  1353. pGuid = WmipGuidMapHandleToGuid(
  1354. &pContext->GuidMapListHead,
  1355. pInstanceHeader->ParentRegHandle);
  1356. if (pGuid != NULL) {
  1357. pEvent->ParentGuid = *pGuid;
  1358. }
  1359. #ifdef DBG
  1360. else {
  1361. WmipAssert(pGuid != NULL);
  1362. }
  1363. #endif
  1364. }
  1365. if (UseBasePtr) {
  1366. pEvent->Header.Size = pInstanceHeader->Size;
  1367. pEvent->MofData = (PVOID)pHeader;
  1368. pEvent->MofLength = pInstanceHeader->Size;
  1369. if (UsePerfClock == EVENT_TRACE_CLOCK_PERFCOUNTER) {
  1370. pInstanceHeader->TimeStamp = pWnode->TimeStamp;
  1371. }
  1372. }
  1373. else {
  1374. pEvent->Header.FieldTypeFlags = (PrivateLogger) ? EVENT_TRACE_USE_PROCTIME : 0;
  1375. if (pInstanceHeader->Size > sizeof(EVENT_INSTANCE_HEADER)) {
  1376. pEvent->MofData = (PVOID) ((char*)pInstanceHeader +
  1377. sizeof(EVENT_INSTANCE_HEADER));
  1378. pEvent->MofLength = pInstanceHeader->Size -
  1379. sizeof(EVENT_INSTANCE_HEADER);
  1380. }
  1381. }
  1382. break;
  1383. }
  1384. case TRACE_HEADER_TYPE_TIMED:
  1385. {
  1386. PTIMED_TRACE_HEADER pTimedHeader;
  1387. pTimedHeader = (PTIMED_TRACE_HEADER) pHeader;
  1388. RtlZeroMemory(pEvent, sizeof(EVENT_TRACE));
  1389. pWnode = (PEVENT_TRACE_HEADER) &pEvent->Header;
  1390. pWnode->Size = pTimedHeader->Size;
  1391. pWnode->Version = pTimedHeader->EventId;
  1392. WmipCalculateCurrentTime( &pWnode->TimeStamp,
  1393. &pTimedHeader->TimeStamp,
  1394. pContext );
  1395. pWnode->ThreadId = -1;
  1396. pWnode->ProcessId = -1;
  1397. if (UseBasePtr) {
  1398. pEvent->MofData = (PVOID)pHeader;
  1399. pEvent->MofLength = pTimedHeader->Size;
  1400. if (UsePerfClock == EVENT_TRACE_CLOCK_PERFCOUNTER) {
  1401. pTimedHeader->TimeStamp = pWnode->TimeStamp;
  1402. }
  1403. }
  1404. else if (pWnode->Size > sizeof(TIMED_TRACE_HEADER)) {
  1405. pEvent->MofData = (PVOID) ((char*) pHeader +
  1406. sizeof(TIMED_TRACE_HEADER));
  1407. pEvent->MofLength = pWnode->Size - sizeof(TIMED_TRACE_HEADER);
  1408. }
  1409. pEvent->Header.FieldTypeFlags = EVENT_TRACE_USE_NOCPUTIME;
  1410. break;
  1411. }
  1412. case TRACE_HEADER_TYPE_WNODE_HEADER:
  1413. {
  1414. PWNODE_HEADER pWnode = (PWNODE_HEADER) pHeader;
  1415. RtlZeroMemory(pEvent, sizeof(EVENT_TRACE));
  1416. RtlCopyMemory(&pEvent->Header, pWnode, sizeof(WNODE_HEADER));
  1417. pEvent->MofData = (PVOID) pWnode;
  1418. pEvent->MofLength = pWnode->BufferSize;
  1419. break;
  1420. }
  1421. case TRACE_HEADER_TYPE_MESSAGE:
  1422. {
  1423. PMESSAGE_TRACE pMsg = (PMESSAGE_TRACE) pHeader ;
  1424. RtlZeroMemory(pEvent, sizeof(EVENT_TRACE));
  1425. RtlCopyMemory(&pEvent->Header, pMsg, sizeof(MESSAGE_TRACE_HEADER)) ;
  1426. if (UseBasePtr) {
  1427. pEvent->MofData = (PVOID)pHeader;
  1428. pEvent->MofLength = pMsg->MessageHeader.Size;
  1429. }
  1430. else {
  1431. pEvent->MofData = (PVOID)&(pMsg->Data) ;
  1432. pEvent->MofLength = pMsg->MessageHeader.Size - sizeof(MESSAGE_TRACE_HEADER) ;
  1433. }
  1434. break;
  1435. }
  1436. default: // Assumed to be REAL WNODE
  1437. break;
  1438. }
  1439. return WmipSetDosError(ERROR_SUCCESS);
  1440. }
  1441. ULONG
  1442. WmipGetNextEventOffsetType(
  1443. PUCHAR pBuffer,
  1444. ULONG Offset,
  1445. PULONG RetSize
  1446. )
  1447. {
  1448. ULONG nSize;
  1449. ULONG TraceMarker;
  1450. ULONG TraceType = 0;
  1451. PWMI_BUFFER_HEADER Header = (PWMI_BUFFER_HEADER)pBuffer;
  1452. ULONG Alignment = Header->ClientContext.Alignment;
  1453. ULONG BufferSize = Header->Wnode.BufferSize;
  1454. *RetSize = 0;
  1455. //
  1456. // Check for end of buffer (w/o End of Buffer Marker case...)
  1457. //
  1458. if ( Offset >= (BufferSize - sizeof(long)) ){
  1459. return 0;
  1460. }
  1461. TraceMarker = *((PULONG)(pBuffer + Offset));
  1462. if (TraceMarker == 0xFFFFFFFF) {
  1463. return 0;
  1464. }
  1465. if (TraceMarker & TRACE_HEADER_FLAG) {
  1466. //
  1467. // If the first bit is set, then it is either TRACE or PERF record.
  1468. //
  1469. if (TraceMarker & TRACE_HEADER_EVENT_TRACE) { // One of Ours.
  1470. TraceType = (TraceMarker & TRACE_HEADER_ENUM_MASK) >> 16;
  1471. switch(TraceType) {
  1472. //
  1473. // ISSUE: Need to split the two so we can process cross platform.
  1474. // shsiao 03/22/2000
  1475. //
  1476. case TRACE_HEADER_TYPE_PERFINFO32:
  1477. case TRACE_HEADER_TYPE_PERFINFO64:
  1478. {
  1479. PUSHORT Size;
  1480. Size = (PUSHORT) (pBuffer + Offset + sizeof(ULONG));
  1481. nSize = *Size;
  1482. break;
  1483. }
  1484. case TRACE_HEADER_TYPE_SYSTEM32:
  1485. case TRACE_HEADER_TYPE_SYSTEM64:
  1486. {
  1487. PUSHORT Size;
  1488. Size = (PUSHORT) (pBuffer + Offset + sizeof(ULONG));
  1489. nSize = *Size;
  1490. break;
  1491. }
  1492. case TRACE_HEADER_TYPE_FULL_HEADER:
  1493. case TRACE_HEADER_TYPE_INSTANCE:
  1494. {
  1495. PUSHORT Size;
  1496. Size = (PUSHORT)(pBuffer + Offset);
  1497. nSize = *Size;
  1498. break;
  1499. }
  1500. default:
  1501. {
  1502. return 0;
  1503. }
  1504. }
  1505. }
  1506. else if ((TraceMarker & TRACE_HEADER_ULONG32_TIME) ==
  1507. TRACE_HEADER_ULONG32_TIME) {
  1508. PUSHORT Size;
  1509. Size = (PUSHORT) (pBuffer + Offset);
  1510. nSize = *Size;
  1511. TraceType = TRACE_HEADER_TYPE_TIMED;
  1512. }
  1513. else if ((TraceMarker & TRACE_HEADER_ULONG32) ==
  1514. TRACE_HEADER_ULONG32) {
  1515. PUSHORT Size;
  1516. Size = (PUSHORT) (pBuffer + Offset);
  1517. nSize = *Size;
  1518. TraceType = TRACE_HEADER_TYPE_ULONG32;
  1519. }
  1520. else if ((TraceMarker & TRACE_MESSAGE) ==
  1521. TRACE_MESSAGE) {
  1522. PUSHORT Size;
  1523. Size = (PUSHORT) (pBuffer + Offset) ;
  1524. nSize = *Size;
  1525. TraceType = TRACE_HEADER_TYPE_MESSAGE;
  1526. }
  1527. else {
  1528. return 0;
  1529. }
  1530. }
  1531. else { // Must be WNODE_HEADER
  1532. PUSHORT Size;
  1533. Size = (PUSHORT) (pBuffer + Offset);
  1534. nSize = *Size;
  1535. TraceType = TRACE_HEADER_TYPE_WNODE_HEADER;
  1536. }
  1537. //
  1538. // Check for End Of Buffer Marker
  1539. //
  1540. if (nSize == 0xFFFFFFFF) {
  1541. return 0;
  1542. }
  1543. //
  1544. // Check for larger than BufferSize
  1545. //
  1546. if (nSize >= BufferSize) {
  1547. return 0;
  1548. }
  1549. if (Alignment != 0) {
  1550. nSize = (ULONG) ALIGN_TO_POWER2(nSize, Alignment);
  1551. }
  1552. *RetSize = nSize;
  1553. return TraceType;
  1554. }
  1555. ULONG
  1556. WmipReadGuidMapRecords(
  1557. PEVENT_TRACE_LOGFILEW logfile,
  1558. PVOID pBuffer,
  1559. BOOLEAN bLogFileHeader
  1560. )
  1561. {
  1562. PEVENT_TRACE pEvent;
  1563. EVENT_TRACE EventTrace;
  1564. ULONG BufferSize;
  1565. ULONG Status;
  1566. WMI_HEADER_TYPE HeaderType = WMIHT_NONE;
  1567. ULONG Size;
  1568. ULONG Offset;
  1569. PTRACELOG_CONTEXT pContext = logfile->Context;
  1570. Offset = sizeof(WMI_BUFFER_HEADER);
  1571. while (TRUE) {
  1572. pEvent = &EventTrace;
  1573. RtlZeroMemory(pEvent, sizeof(EVENT_TRACE) );
  1574. HeaderType = WmiGetTraceHeader(pBuffer, Offset, &Size);
  1575. if ( (HeaderType == WMIHT_NONE) ||
  1576. (HeaderType == WMIHT_WNODE) ||
  1577. (Size == 0)
  1578. ) {
  1579. break;
  1580. }
  1581. Status = WmipParseTraceEvent(pContext, pBuffer, Offset, HeaderType, pEvent, sizeof(EVENT_TRACE));
  1582. Offset += Size;
  1583. if (IsEqualGUID(&pEvent->Header.Guid, &EventTraceGuid)
  1584. && (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_GUIDMAP))
  1585. {
  1586. WmipGuidMapCallback(&pContext->GuidMapListHead, pEvent);
  1587. //
  1588. // If we are processing the events in raw base pointer mode,
  1589. // we fire callbacks for guid maps also. Note that only the
  1590. // GuidMaps at the start of the file are triggered. The ones at the
  1591. // end are ignored. This is because the time order needs to be
  1592. // preserved when firing callbacks to the user.
  1593. //
  1594. if (bLogFileHeader && (pContext->ConversionFlags & EVENT_TRACE_GET_RAWEVENT)) {
  1595. Status = WmipDoEventCallbacks( logfile, pEvent);
  1596. if (Status != ERROR_SUCCESS) {
  1597. break;
  1598. }
  1599. }
  1600. }
  1601. else {
  1602. if (bLogFileHeader) {
  1603. Status = WmipDoEventCallbacks( logfile, pEvent);
  1604. if (Status != ERROR_SUCCESS) {
  1605. break;
  1606. }
  1607. }
  1608. else {
  1609. return ERROR_INVALID_DATA;
  1610. }
  1611. }
  1612. }
  1613. return ERROR_SUCCESS;
  1614. }
  1615. ULONG
  1616. WmipProcessGuidMaps(
  1617. PEVENT_TRACE_LOGFILEW *Logfiles,
  1618. ULONG LogfileCount,
  1619. ULONG Unicode
  1620. )
  1621. {
  1622. long i;
  1623. NTSTATUS Status;
  1624. PTRACELOG_CONTEXT pContext;
  1625. PEVENT_TRACE_LOGFILEW logfile;
  1626. ULONG BuffersWritten;
  1627. ULONG BufferSize, nBytesRead;
  1628. ULONGLONG SizeWritten, ReadPosition;
  1629. PVOID pBuffer;
  1630. for (i=0; i<(long)LogfileCount; i++) {
  1631. logfile = Logfiles[i];
  1632. if (Logfiles[i]->LogFileMode & EVENT_TRACE_REAL_TIME_MODE) {
  1633. continue;
  1634. }
  1635. if (logfile->IsKernelTrace) {
  1636. continue;
  1637. }
  1638. pContext = (PTRACELOG_CONTEXT) logfile->Context;
  1639. if (pContext == NULL) {
  1640. continue;
  1641. }
  1642. //
  1643. // We now start reading the GuidMaps at the end of file.
  1644. //
  1645. if (!(Logfiles[i]->LogFileMode & EVENT_TRACE_FILE_MODE_CIRCULAR))
  1646. {
  1647. pContext->fGuidMapRead = FALSE;
  1648. }
  1649. BuffersWritten = logfile->LogfileHeader.BuffersWritten;
  1650. BufferSize = pContext->BufferSize;
  1651. SizeWritten = BuffersWritten * BufferSize;
  1652. if (Logfiles[i]->LogFileMode & EVENT_TRACE_FILE_MODE_CIRCULAR) {
  1653. ULONGLONG maxFileSize = (logfile->LogfileHeader.MaximumFileSize
  1654. * 1024 * 1024);
  1655. if ( (maxFileSize > 0) && (SizeWritten > maxFileSize) ) {
  1656. SizeWritten = maxFileSize;
  1657. }
  1658. }
  1659. pBuffer = WmipAlloc(BufferSize);
  1660. if (pBuffer == NULL) {
  1661. return WmipSetDosError(ERROR_OUTOFMEMORY);
  1662. }
  1663. RtlZeroMemory(pBuffer, BufferSize);
  1664. ReadPosition = SizeWritten;
  1665. while (TRUE) {
  1666. if (!GetOverlappedResult(pContext->Handle, &pContext->AsynchRead, &nBytesRead, TRUE) &&
  1667. GetLastError() != ERROR_HANDLE_EOF) {
  1668. WmipDebugPrint(("GetOverlappedResult failed with Status %d in ProcessGuidMaps\n", GetLastError()));
  1669. break;
  1670. }
  1671. pContext->AsynchRead.Offset = (DWORD)(ReadPosition & 0xFFFFFFFF);
  1672. pContext->AsynchRead.OffsetHigh = (DWORD)(ReadPosition >> 32);
  1673. Status = WmipSynchReadFile(pContext->Handle,
  1674. (LPVOID)pBuffer,
  1675. BufferSize,
  1676. &nBytesRead,
  1677. &pContext->AsynchRead);
  1678. if (nBytesRead == 0) {
  1679. break;
  1680. }
  1681. Status = WmipReadGuidMapRecords(Logfiles[i], pBuffer, FALSE);
  1682. if (Status != ERROR_SUCCESS) {
  1683. break;
  1684. // WmipFree(pBuffer);
  1685. // return Status;
  1686. }
  1687. ReadPosition += BufferSize;
  1688. }
  1689. //
  1690. // End of File was reached. Now set the File Pointer back to
  1691. // the top of the file and process it.
  1692. pContext->StartBuffer = 0;
  1693. ReadPosition = 0;
  1694. while (TRUE) {
  1695. BOOLEAN bLogFileHeader;
  1696. if (!GetOverlappedResult(pContext->Handle, &pContext->AsynchRead, &nBytesRead, TRUE) &&
  1697. GetLastError() != ERROR_HANDLE_EOF) {
  1698. WmipDebugPrint(("GetOverlappedResult failed with Status %d in ProcessGuidMaps\n", GetLastError()));
  1699. break;
  1700. }
  1701. pContext->AsynchRead.Offset = (DWORD)(ReadPosition & 0xFFFFFFFF);
  1702. pContext->AsynchRead.OffsetHigh = (DWORD)(ReadPosition >> 32);
  1703. Status = WmipSynchReadFile(pContext->Handle,
  1704. (LPVOID)pBuffer,
  1705. BufferSize,
  1706. &nBytesRead,
  1707. &pContext->AsynchRead);
  1708. if (nBytesRead == 0) {
  1709. break;
  1710. }
  1711. bLogFileHeader = (pContext->StartBuffer == 0);
  1712. Status = WmipReadGuidMapRecords(Logfiles[i], pBuffer, bLogFileHeader );
  1713. if (Status != ERROR_SUCCESS){
  1714. break;
  1715. }
  1716. pContext->StartBuffer++;
  1717. ReadPosition += BufferSize;
  1718. }
  1719. WmipFree(pBuffer);
  1720. }
  1721. return ERROR_SUCCESS;
  1722. }
  1723. ULONG
  1724. WmipGetBuffersWrittenFromQuery(
  1725. LPWSTR LoggerName
  1726. )
  1727. /*++
  1728. Routine Description:
  1729. This routine returns the number of buffers written by querying a logger.
  1730. In case of an array of LogFiles, this routine should be called individually for
  1731. each one.
  1732. Arguments:
  1733. LogFile - pointer to EVENT_TRACE_LOGFILEW under consideration
  1734. Unicode - whether the logger name is in unicode or not
  1735. Returned Value:
  1736. The number of buffers written.
  1737. --*/
  1738. {
  1739. TRACEHANDLE LoggerHandle = 0;
  1740. ULONG Status;
  1741. RtlZeroMemory(&Properties, sizeof(Properties));
  1742. Properties.TraceProp.Wnode.BufferSize = sizeof(Properties);
  1743. Status = ControlTraceW(LoggerHandle,
  1744. LoggerName,
  1745. &Properties.TraceProp,
  1746. EVENT_TRACE_CONTROL_QUERY);
  1747. if (Status == ERROR_SUCCESS) {
  1748. return Properties.TraceProp.BuffersWritten;
  1749. }
  1750. else {
  1751. SetLastError(Status);
  1752. return 0;
  1753. }
  1754. }
  1755. VOID
  1756. WmipCopyLogHeader (
  1757. IN PTRACE_LOGFILE_HEADER pOutHeader,
  1758. IN PVOID MofData,
  1759. IN ULONG MofLength,
  1760. IN PWCHAR *LoggerName,
  1761. IN PWCHAR *LogFileName,
  1762. IN ULONG Unicode
  1763. )
  1764. {
  1765. PUCHAR Src, Dest;
  1766. PTRACE_LOGFILE_HEADER pInHeader;
  1767. ULONG PointerSize;
  1768. ULONG SizeToCopy;
  1769. ULONG Offset;
  1770. pInHeader = (PTRACE_LOGFILE_HEADER) MofData;
  1771. PointerSize = pInHeader->PointerSize; // This is the PointerSize in File
  1772. if ( (PointerSize != 4) && (PointerSize != 8) ) {
  1773. #ifdef DBG
  1774. WmipDebugPrint(("WMI: Invalid PointerSize in File %d\n",PointerSize));
  1775. #endif
  1776. return;
  1777. }
  1778. //
  1779. // We have Two pointers (LPWSTR) in the middle of the LOGFILE_HEADER
  1780. // structure. So We copy upto the Pointer Fields first, skip over
  1781. // the pointers and copy the remaining stuff. We come back and fixup
  1782. // the pointers appropriately.
  1783. //
  1784. SizeToCopy = FIELD_OFFSET(TRACE_LOGFILE_HEADER, LoggerName);
  1785. RtlCopyMemory(pOutHeader, pInHeader, SizeToCopy);
  1786. //
  1787. // Skip over the Troublesome pointers in both Src and Dest
  1788. //
  1789. Dest = (PUCHAR)pOutHeader + SizeToCopy + 2 * sizeof(LPWSTR);
  1790. Src = (PUCHAR)pInHeader + SizeToCopy + 2 * PointerSize;
  1791. //
  1792. // Copy the Remaining fields at the tail end of the LOGFILE_HEADER
  1793. //
  1794. SizeToCopy = sizeof(TRACE_LOGFILE_HEADER) -
  1795. FIELD_OFFSET(TRACE_LOGFILE_HEADER, TimeZone);
  1796. RtlCopyMemory(Dest, Src, SizeToCopy);
  1797. //
  1798. // Adjust the pointer fields now
  1799. //
  1800. Offset = sizeof(TRACE_LOGFILE_HEADER) -
  1801. 2 * sizeof(LPWSTR) +
  1802. 2 * PointerSize;
  1803. *LoggerName = (PWCHAR) ((PUCHAR)pInHeader + Offset);
  1804. pOutHeader->LoggerName = *LoggerName;
  1805. }
  1806. ULONG
  1807. WmipProcessLogHeader(
  1808. PTRACEHANDLE HandleArray,
  1809. PEVENT_TRACE_LOGFILEW *Logfiles,
  1810. ULONG LogfileCount,
  1811. ULONG Unicode,
  1812. ULONG bFree
  1813. )
  1814. /*++
  1815. Routine Description:
  1816. This routine processes the header of an array of logfiles.
  1817. Arguments:
  1818. LogFile Array of Logfiles being processed.
  1819. LogFileCount Number of Logfiles in the Array.
  1820. Unicode Unicode Flag.
  1821. Returned Value:
  1822. Status Code.
  1823. --*/
  1824. {
  1825. HANDLE hFile;
  1826. PTRACELOG_CONTEXT pContext = NULL;
  1827. PVOID pBuffer;
  1828. PEVENT_TRACE pEvent;
  1829. long i;
  1830. WMI_HEADER_TYPE HeaderType = WMIHT_NONE;
  1831. ULONG Size;
  1832. ULONG Offset;
  1833. LPWSTR loggerName, logFileName;
  1834. ULONG BufferSize, nBytesRead;
  1835. PTRACE_LOGFILE_HEADER logfileHeader;
  1836. ULONG Status = ERROR_SUCCESS;
  1837. //
  1838. // Open the Log File for shared Read
  1839. //
  1840. BufferSize = DEFAULT_LOG_BUFFER_SIZE; // Log file header must be smaller than 1K
  1841. pBuffer = WmipAlloc(BufferSize);
  1842. if (pBuffer == NULL) {
  1843. return WmipSetDosError(ERROR_OUTOFMEMORY);
  1844. }
  1845. for (i=0; i<(long)LogfileCount; i++) {
  1846. EVENT_TRACE EventTrace;
  1847. ULONG SavedConversionFlags;
  1848. OVERLAPPED LogHeaderOverlapped;
  1849. //
  1850. // Caller can pass in Flags to fetch the timestamps in raw mode.
  1851. // Since LogFileHeader gets overwritten from with data from the logfile
  1852. // we need to save the passed in value here.
  1853. //
  1854. SavedConversionFlags = Logfiles[i]->LogfileHeader.ReservedFlags;
  1855. if (Unicode) {
  1856. hFile = CreateFileW(
  1857. (LPWSTR) Logfiles[i]->LogFileName,
  1858. GENERIC_READ,
  1859. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1860. NULL,
  1861. OPEN_EXISTING,
  1862. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
  1863. NULL
  1864. );
  1865. }
  1866. else {
  1867. hFile = CreateFileA(
  1868. (LPSTR) Logfiles[i]->LogFileName,
  1869. GENERIC_READ,
  1870. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1871. NULL,
  1872. OPEN_EXISTING,
  1873. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
  1874. NULL
  1875. );
  1876. }
  1877. if (hFile == INVALID_HANDLE_VALUE) {
  1878. Status = WmipSetDosError(ERROR_BAD_PATHNAME);
  1879. break;
  1880. }
  1881. BufferSize = DEFAULT_LOG_BUFFER_SIZE;
  1882. RtlZeroMemory(pBuffer, BufferSize);
  1883. LogHeaderOverlapped.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
  1884. if (LogHeaderOverlapped.hEvent == NULL) {
  1885. // cannot create event for file read
  1886. break;
  1887. }
  1888. LogHeaderOverlapped.Offset = 0;
  1889. LogHeaderOverlapped.OffsetHigh = 0;
  1890. Status = WmipSynchReadFile(hFile,
  1891. (LPVOID)pBuffer,
  1892. BufferSize,
  1893. &nBytesRead,
  1894. &LogHeaderOverlapped);
  1895. if (nBytesRead == 0) {
  1896. NtClose(hFile);
  1897. Status = WmipSetDosError(ERROR_FILE_CORRUPT);
  1898. break;
  1899. }
  1900. CloseHandle(LogHeaderOverlapped.hEvent);
  1901. Offset = sizeof(WMI_BUFFER_HEADER);
  1902. pEvent = &EventTrace;
  1903. RtlZeroMemory(pEvent, sizeof(EVENT_TRACE) );
  1904. HeaderType = WmiGetTraceHeader(pBuffer, Offset, &Size);
  1905. if ( (HeaderType == WMIHT_NONE) ||
  1906. (HeaderType == WMIHT_WNODE) ||
  1907. (Size == 0)
  1908. ) {
  1909. NtClose(hFile);
  1910. Status = WmipSetDosError(ERROR_FILE_CORRUPT);
  1911. break;
  1912. }
  1913. Status = WmipParseTraceEvent(NULL, pBuffer, Offset, HeaderType, pEvent, sizeof(EVENT_TRACE));
  1914. //
  1915. // Set up the header structure properly
  1916. //
  1917. if ((Status == ERROR_SUCCESS) && (pEvent->MofLength > 0)) {
  1918. ULONG PointerSize;
  1919. logfileHeader = &Logfiles[i]->LogfileHeader;
  1920. //
  1921. // We are relying on the fact that the PointerSize field
  1922. // will not shift between platforms.
  1923. //
  1924. PointerSize = ((PTRACE_LOGFILE_HEADER)(pEvent->MofData))->PointerSize;
  1925. if (PointerSize == sizeof(PUCHAR) ) {
  1926. RtlCopyMemory(&Logfiles[i]->LogfileHeader, pEvent->MofData,
  1927. sizeof(TRACE_LOGFILE_HEADER));
  1928. loggerName = (LPWSTR) ( (char*)pEvent->MofData +
  1929. sizeof(TRACE_LOGFILE_HEADER) );
  1930. // logFileName = (LPWSTR) ( (char*)pEvent->MofData +
  1931. // sizeof(TRACE_LOGFILE_HEADER) +
  1932. // sizeof(WCHAR)* wcslen(loggerName));
  1933. }
  1934. else {
  1935. //
  1936. // Ugly thunking going on here. Close your eyes...
  1937. //
  1938. WmipCopyLogHeader(&Logfiles[i]->LogfileHeader,
  1939. pEvent->MofData,
  1940. pEvent->MofLength,
  1941. &loggerName,
  1942. &logFileName,
  1943. Unicode);
  1944. pEvent->MofData = (PVOID)&Logfiles[i]->LogfileHeader;
  1945. }
  1946. }
  1947. else {
  1948. NtClose(hFile);
  1949. Status = WmipSetDosError(ERROR_FILE_CORRUPT);
  1950. break;
  1951. }
  1952. Logfiles[i]->IsKernelTrace = !wcscmp(loggerName, KERNEL_LOGGER_CAPTION);
  1953. Logfiles[i]->LogFileMode = (logfileHeader->LogFileMode &
  1954. ~(EVENT_TRACE_REAL_TIME_MODE));
  1955. #ifdef DBG
  1956. DbgPrint("Dumping Logfile Header\n");
  1957. DbgPrint("\tStart Time %I64u\n",
  1958. pEvent->Header.TimeStamp);
  1959. DbgPrint("\tLogger Thread Id %X\n",
  1960. pEvent->Header.ThreadId);
  1961. DbgPrint("\tHeader Size %d\n",
  1962. pEvent->Header.Size);
  1963. DbgPrint("\tBufferSize %d\n",
  1964. logfileHeader->BufferSize);
  1965. DbgPrint("\tVersion %d\n",
  1966. logfileHeader->Version);
  1967. DbgPrint("\tProviderVersion %d\n",
  1968. logfileHeader->ProviderVersion);
  1969. DbgPrint("\tEndTime %I64u\n",
  1970. logfileHeader->EndTime);
  1971. DbgPrint("\tTimer Resolution %d\n",
  1972. logfileHeader->TimerResolution);
  1973. DbgPrint("\tMaximum File Size %d\n",
  1974. logfileHeader->MaximumFileSize);
  1975. DbgPrint("\tBuffers Written %d\n",
  1976. logfileHeader->BuffersWritten);
  1977. DbgPrint("\tEvents Lost %d\n",
  1978. logfileHeader->EventsLost);
  1979. DbgPrint("\tBuffers Lost %d\n",
  1980. logfileHeader->BuffersLost);
  1981. DbgPrint("\tStart Buffers%d\n",
  1982. logfileHeader->StartBuffers);
  1983. DbgPrint("\tReserved Flags %x\n",
  1984. logfileHeader->ReservedFlags);
  1985. DbgPrint("\tFrequency %I64u\n",
  1986. logfileHeader->PerfFreq.QuadPart);
  1987. DbgPrint("\tLogger Name %ls\n",
  1988. loggerName);
  1989. DbgPrint("\tStartTime %I64u\n",
  1990. logfileHeader->StartTime.QuadPart);
  1991. // DbgPrint("\tLogfile Name %ls\n",
  1992. // logFileName);
  1993. DbgPrint("\tLogfile Mode %X\n",
  1994. logfileHeader->LogFileMode);
  1995. DbgPrint("\tProcessorCount %d\n",
  1996. logfileHeader->NumberOfProcessors);
  1997. #endif
  1998. if (Logfiles[i]->IsKernelTrace)
  1999. WmipDebugPrint(("\tLogfile contains kernel trace\n"));
  2000. BufferSize = logfileHeader->BufferSize;
  2001. WmipAssert(BufferSize > 0);
  2002. if ( (BufferSize/1024 == 0) ||
  2003. (((BufferSize/1024)*1024) != BufferSize) ) {
  2004. NtClose(hFile);
  2005. Status = WmipSetDosError(ERROR_FILE_CORRUPT);
  2006. break;
  2007. }
  2008. if (Logfiles[i]->IsKernelTrace)
  2009. WmipDebugPrint(("\tLogfile contains kernel trace\n"));
  2010. if (bFree) {
  2011. NtClose(hFile);
  2012. }
  2013. else {
  2014. //
  2015. // At this point, the logfile is opened successfully
  2016. // Initialize the internal context now
  2017. //
  2018. pContext = WmipLookupTraceHandle(HandleArray[i]);
  2019. if (pContext == NULL) {
  2020. NtClose(hFile);
  2021. // TODO: Find an appropriate eerror code here?
  2022. Status = WmipSetDosError(ERROR_OUTOFMEMORY);
  2023. break;
  2024. }
  2025. Logfiles[i]->Context = pContext;
  2026. pContext->Handle = hFile;
  2027. //
  2028. // If the EndTime is 0, then compute the BuffersWritten from
  2029. // FileSize and BufferSize.
  2030. //
  2031. // However, an on-going session with a preallocated log file
  2032. // will use QueryTrace() to get BuffersWritten.
  2033. //
  2034. if (logfileHeader->EndTime.QuadPart == 0) {
  2035. if (logfileHeader->LogFileMode & EVENT_TRACE_FILE_MODE_PREALLOCATE) {
  2036. ULONG QueriedBuffersWritten = WmipGetBuffersWrittenFromQuery(loggerName);
  2037. if (QueriedBuffersWritten) {
  2038. logfileHeader->BuffersWritten = QueriedBuffersWritten;
  2039. }
  2040. }
  2041. else {
  2042. FILE_STANDARD_INFORMATION FileInfo;
  2043. NTSTATUS NtStatus;
  2044. IO_STATUS_BLOCK IoStatus;
  2045. NtStatus = NtQueryInformationFile(
  2046. hFile,
  2047. &IoStatus,
  2048. &FileInfo,
  2049. sizeof(FILE_STANDARD_INFORMATION),
  2050. FileStandardInformation
  2051. );
  2052. if (NT_SUCCESS(NtStatus)) {
  2053. ULONG64 FileSize = FileInfo.AllocationSize.QuadPart;
  2054. ULONG64 BuffersWritten = FileSize / (ULONG64) BufferSize;
  2055. logfileHeader->BuffersWritten = (ULONG) BuffersWritten;
  2056. }
  2057. }
  2058. }
  2059. pContext->BufferCount = logfileHeader->BuffersWritten;
  2060. pContext->BufferSize = logfileHeader->BufferSize;
  2061. pContext->InitialSize = Size;
  2062. //
  2063. // Save the flags from OpenTrace at this time before the first
  2064. // buffer callback which will erase it.
  2065. //
  2066. pContext->ConversionFlags = SavedConversionFlags;
  2067. //
  2068. // Make the header the current Event ...
  2069. // and the callbacks for the header are handled by ProcessTraceLog.
  2070. pContext->UsePerfClock = logfileHeader->ReservedFlags;
  2071. pContext->StartTime = logfileHeader->StartTime;
  2072. pContext->PerfFreq = logfileHeader->PerfFreq;
  2073. pContext->CpuSpeedInMHz = logfileHeader->CpuSpeedInMHz;
  2074. //
  2075. // If the conversion flags are set, adjust UsePerfClock accordingly.
  2076. //
  2077. if (pContext->ConversionFlags & EVENT_TRACE_USE_RAWTIMESTAMP) {
  2078. pContext->UsePerfClock = EVENT_TRACE_CLOCK_RAW;
  2079. }
  2080. if ((pContext->UsePerfClock == EVENT_TRACE_CLOCK_PERFCOUNTER) ||
  2081. (pContext->UsePerfClock == EVENT_TRACE_CLOCK_CPUCYCLE) ) {
  2082. pContext->StartPerfClock = pEvent->Header.TimeStamp;
  2083. Logfiles[i]->CurrentTime = pContext->StartTime.QuadPart;
  2084. pEvent->Header.TimeStamp.QuadPart = pContext->StartTime.QuadPart;
  2085. }
  2086. else {
  2087. Logfiles[i]->CurrentTime = pEvent->Header.TimeStamp.QuadPart;
  2088. }
  2089. }
  2090. }
  2091. WmipFree(pBuffer);
  2092. return Status;
  2093. }
  2094. ULONG
  2095. WmipDoEventCallbacks(
  2096. PEVENT_TRACE_LOGFILEW logfile,
  2097. PEVENT_TRACE pEvent
  2098. )
  2099. {
  2100. NTSTATUS Status;
  2101. PEVENT_TRACE_CALLBACK pCallback;
  2102. //
  2103. // First the Generic Event Callback is called.
  2104. //
  2105. if ( logfile->EventCallback ) {
  2106. try {
  2107. (*logfile->EventCallback)(pEvent);
  2108. } except (EXCEPTION_EXECUTE_HANDLER) {
  2109. Status = GetExceptionCode();
  2110. #ifdef DBG
  2111. WmipDebugPrint(("TRACE: EventCallback threw exception %X\n",
  2112. Status));
  2113. #endif
  2114. return WmipSetDosError(WmipNtStatusToDosError(Status));
  2115. }
  2116. }
  2117. //
  2118. // Now Call the event specific callback.
  2119. //
  2120. pCallback = WmipGetCallbackRoutine( &pEvent->Header.Guid );
  2121. if ( pCallback != NULL ) {
  2122. try {
  2123. (*pCallback->CallbackRoutine)(pEvent);
  2124. } except (EXCEPTION_EXECUTE_HANDLER) {
  2125. Status = GetExceptionCode();
  2126. #ifdef DBG
  2127. WmipDebugPrint(("EventCallback %X threw exception %X\n",
  2128. pCallback->CallbackRoutine, Status));
  2129. #endif
  2130. return WmipSetDosError(WmipNtStatusToDosError(Status));
  2131. }
  2132. }
  2133. logfile->CurrentTime = pEvent->Header.TimeStamp.QuadPart;
  2134. return ERROR_SUCCESS;
  2135. }
  2136. ULONG
  2137. WmipAdvanceToNewEvent(
  2138. PEVENT_TRACE_LOGFILEW logfile,
  2139. BOOL EventInRange
  2140. )
  2141. {
  2142. ULONG Status = ERROR_SUCCESS;
  2143. PEVENT_TRACE pEvent;
  2144. PTRACELOG_CONTEXT pContext;
  2145. PVOID pBuffer;
  2146. PTRACE_BUFFER_LIST_ENTRY Current;
  2147. ULONG Size;
  2148. WMI_HEADER_TYPE HeaderType = WMIHT_NONE;
  2149. pContext = logfile->Context;
  2150. if (pContext == NULL) {
  2151. return WmipSetDosError(ERROR_INVALID_PARAMETER);
  2152. }
  2153. Current = WmipRemoveBuffer(&pContext->Root);
  2154. if (Current == NULL) {
  2155. pContext->EndOfFile = TRUE;
  2156. return ERROR_SUCCESS;
  2157. }
  2158. //
  2159. // Advance Event for current buffer
  2160. //
  2161. pEvent = &Current->Event;
  2162. //
  2163. // Before we make the callbacks, we need to restore the
  2164. // raw buffer, so that MofData will be pointing to the right data.
  2165. //
  2166. pBuffer = WmipGetCurrentBuffer(pContext, Current);
  2167. if (pBuffer == NULL) {
  2168. //
  2169. // This condition could happen when the file we are reading
  2170. // gets overwritten.
  2171. //
  2172. return ERROR_SHARING_VIOLATION;
  2173. }
  2174. if (EventInRange) {
  2175. Status = WmipDoEventCallbacks( logfile, pEvent);
  2176. if (Status != ERROR_SUCCESS) {
  2177. return Status;
  2178. }
  2179. }
  2180. Size = 0;
  2181. if ((HeaderType = WmiGetTraceHeader(pBuffer, Current->BufferOffset, &Size)) != WMIHT_NONE) {
  2182. if (Size > 0) {
  2183. Status = WmipParseTraceEvent(pContext, pBuffer, Current->BufferOffset, HeaderType, pEvent, sizeof(EVENT_TRACE));
  2184. Current->BufferOffset += Size;
  2185. Current->TraceType = WmipConvertEnumToTraceType(HeaderType);
  2186. }
  2187. }
  2188. Current->EventSize = Size;
  2189. if ( ( Size > 0) && (Status == ERROR_SUCCESS) ) {
  2190. WmipInsertBuffer(&pContext->Root, Current);
  2191. }
  2192. else {
  2193. DWORD BytesTransffered;
  2194. //
  2195. // When the current buffer is exhausted, make the
  2196. // BufferCallback
  2197. //
  2198. if (logfile->BufferCallback) {
  2199. ULONG bRetVal;
  2200. PWMI_BUFFER_HEADER pHeader = (PWMI_BUFFER_HEADER)pBuffer;
  2201. logfile->Filled = (ULONG)pHeader->Offset;
  2202. logfile->EventsLost = pHeader->EventsLost;
  2203. try {
  2204. bRetVal = (*logfile->BufferCallback) (logfile);
  2205. if (!bRetVal) {
  2206. return ERROR_CANCELLED;
  2207. }
  2208. } except (EXCEPTION_EXECUTE_HANDLER) {
  2209. pContext->EndOfFile = TRUE;
  2210. Status = GetExceptionCode();
  2211. #ifdef DBG
  2212. WmipDebugPrint(("TRACE: BufferCallback threw exception %X\n",
  2213. Status));
  2214. #endif
  2215. WmipSetDosError(WmipNtStatusToDosError(Status));
  2216. return ERROR_CANCELLED; // so that realtime also cleans up.
  2217. }
  2218. }
  2219. //
  2220. // Issue another asynch read on this buffer cache slot if there are no outstanding reads
  2221. // at this point.
  2222. // GetOverlappedResult() returns FALSE if IO is still pending.
  2223. //
  2224. if (pContext->BufferBeingRead == -1 ||
  2225. GetOverlappedResult(pContext->Handle, &pContext->AsynchRead, &BytesTransffered, FALSE)) {
  2226. LONG FileOffset = Current->FileOffset + MAX_TRACE_BUFFER_CACHE_SIZE;
  2227. if ((ULONG)FileOffset < pContext->BufferCount) {
  2228. ULONGLONG Offset = FileOffset * pContext->BufferSize;
  2229. ResetEvent(pContext->AsynchRead.hEvent);
  2230. pContext->AsynchRead.Offset = (DWORD)(Offset & 0xFFFFFFFF);
  2231. pContext->AsynchRead.OffsetHigh = (DWORD)(Offset >> 32);
  2232. Status = ReadFile(pContext->Handle,
  2233. (LPVOID)pBuffer,
  2234. pContext->BufferSize,
  2235. NULL,
  2236. &pContext->AsynchRead);
  2237. if (Status || GetLastError() == ERROR_IO_PENDING) {
  2238. ULONG TableIndex = FileOffset % MAX_TRACE_BUFFER_CACHE_SIZE;
  2239. pContext->BufferBeingRead = FileOffset;
  2240. pContext->BufferCache[TableIndex].Index = FileOffset;
  2241. }
  2242. else { // Issuing asynch IO failed. Not a fatal error. Just continue for now.
  2243. SetEvent(pContext->AsynchRead.hEvent);
  2244. pContext->BufferBeingRead = -1;
  2245. }
  2246. }
  2247. }
  2248. }
  2249. //
  2250. // The File reaches end of file when the Root is NULL
  2251. //
  2252. if (pContext->Root == NULL) {
  2253. pContext->EndOfFile = TRUE;
  2254. }
  2255. else {
  2256. logfile->CurrentTime = pContext->Root->Event.Header.TimeStamp.QuadPart;
  2257. }
  2258. return ERROR_SUCCESS;
  2259. }
  2260. ULONG
  2261. WmipBuildEventTable(
  2262. PTRACELOG_CONTEXT pContext
  2263. )
  2264. {
  2265. ULONG i, nBytesRead;
  2266. PVOID pBuffer;
  2267. ULONG BufferSize = pContext->BufferSize;
  2268. PEVENT_TRACE pEvent;
  2269. ULONG TotalBuffersRead;
  2270. NTSTATUS Status;
  2271. ULONGLONG ReadPosition;
  2272. //
  2273. // File is already open.
  2274. // Reset the file pointer and continue.
  2275. // TODO: If we start at bottom of file and insert
  2276. // it might be more efficient.
  2277. //
  2278. ReadPosition = pContext->StartBuffer * BufferSize;
  2279. TotalBuffersRead = pContext->StartBuffer;
  2280. //
  2281. // If there are no other buffers except header and guidmaps, EOF is true
  2282. //
  2283. if (TotalBuffersRead == pContext->BufferCount) {
  2284. pContext->EndOfFile = TRUE;
  2285. pContext->Root = NULL;
  2286. return ERROR_SUCCESS;
  2287. }
  2288. do {
  2289. WMI_HEADER_TYPE HeaderType = WMIHT_NONE;
  2290. ULONG Size;
  2291. ULONG Offset;
  2292. ULONG TableIndex;
  2293. TableIndex = TotalBuffersRead % MAX_TRACE_BUFFER_CACHE_SIZE ;
  2294. pBuffer = pContext->BufferCache[TableIndex].Buffer;
  2295. if (!GetOverlappedResult(pContext->Handle, &pContext->AsynchRead, &nBytesRead, TRUE) &&
  2296. GetLastError() != ERROR_HANDLE_EOF) {
  2297. WmipDebugPrint(("GetOverlappedResult failed with Status %d in BuildEventTable\n", GetLastError()));
  2298. break;
  2299. }
  2300. pContext->AsynchRead.Offset = (DWORD)(ReadPosition & 0xFFFFFFFF);
  2301. pContext->AsynchRead.OffsetHigh = (DWORD)(ReadPosition >> 32);
  2302. Status = WmipSynchReadFile(pContext->Handle,
  2303. (LPVOID)pBuffer,
  2304. BufferSize,
  2305. &nBytesRead,
  2306. &pContext->AsynchRead);
  2307. if (nBytesRead == 0)
  2308. break;
  2309. ReadPosition += BufferSize;
  2310. Offset = sizeof(WMI_BUFFER_HEADER);
  2311. pEvent = &pContext->BufferList[TotalBuffersRead].Event;
  2312. HeaderType = WmiGetTraceHeader(pBuffer, Offset, &Size);
  2313. if ( (HeaderType == WMIHT_NONE) || (HeaderType == WMIHT_WNODE) || (Size == 0) ) {
  2314. TotalBuffersRead++;
  2315. continue;
  2316. }
  2317. Status = WmipParseTraceEvent(pContext, pBuffer, Offset, HeaderType, pEvent, sizeof(EVENT_TRACE));
  2318. //
  2319. // Set up the header structure properly
  2320. //
  2321. if (Status != ERROR_SUCCESS) {
  2322. TotalBuffersRead++;
  2323. continue;
  2324. }
  2325. Offset += Size;
  2326. pContext->BufferList[TotalBuffersRead].BufferOffset = Offset;
  2327. pContext->BufferList[TotalBuffersRead].FileOffset = TotalBuffersRead;
  2328. pContext->BufferList[TotalBuffersRead].EventSize = Size;
  2329. pContext->BufferList[TotalBuffersRead].TraceType = WmipConvertEnumToTraceType(HeaderType);
  2330. WmipInsertBuffer(&pContext->Root, &pContext->BufferList[TotalBuffersRead]);
  2331. TotalBuffersRead++;
  2332. if (TotalBuffersRead >= pContext->BufferCount) {
  2333. break;
  2334. }
  2335. } while (1);
  2336. return ERROR_SUCCESS;
  2337. }
  2338. ULONG
  2339. WmipProcessTraceLog(
  2340. PTRACEHANDLE HandleArray,
  2341. PEVENT_TRACE_LOGFILEW *Logfiles,
  2342. ULONG LogfileCount,
  2343. LONGLONG StartTime,
  2344. LONGLONG EndTime,
  2345. ULONG Unicode
  2346. )
  2347. /*++
  2348. Routine Description:
  2349. This routine processes an array of traces (from file or realtime input
  2350. stream). If the trace is from a file, goes through each event till the
  2351. end of file, firing event callbacks (if any) along the way. If the trace
  2352. is from realtime, it waits for event notification about buffer delivery
  2353. from the realtime callback and processes the buffer delivered in the
  2354. same way. It handles circular logfiles and windowing of data (with the
  2355. given start and end times) correctly. When more than one trace it
  2356. provides the callback in chronological order.
  2357. Arguments:
  2358. Logfiles Array of traces
  2359. LogfileCount Number of traces
  2360. StartTime Starting Time of the window of analysis
  2361. EndTime Ending Time of the window of analysis
  2362. Unicode Unicode Flag.
  2363. Returned Value:
  2364. Status Code.
  2365. --*/
  2366. {
  2367. PEVENT_TRACE_LOGFILE logfile;
  2368. ULONG Status;
  2369. PEVENT_TRACE pEvent;
  2370. PTRACELOG_CONTEXT pContext;
  2371. EVENT_TRACE_PROPERTIES Properties;
  2372. ULONG RealTimeDataFeed, LogFileDataFeed;
  2373. USHORT LoggerId;
  2374. TRACEHANDLE LoggerHandle = 0;
  2375. ULONG i, j;
  2376. BOOL Done = FALSE;
  2377. ACCESS_MASK DesiredAccess = TRACELOG_ACCESS_REALTIME;
  2378. // ContextListHeadPtr = &ContextListHead;
  2379. // InitializeListHead(ContextListHeadPtr);
  2380. Status = WmipCreateGuidMapping();
  2381. if (Status != ERROR_SUCCESS) {
  2382. return Status;
  2383. }
  2384. //
  2385. // After reading the First Buffer, determine the BufferSize,
  2386. // Number of Buffers written, filesize, kernel or non-kernel logger
  2387. // Set a flag to strip out the GuidMap at the end.
  2388. //
  2389. Status = WmipProcessLogHeader( HandleArray, Logfiles, LogfileCount, Unicode, FALSE );
  2390. if (Status != ERROR_SUCCESS) {
  2391. goto Cleanup;
  2392. }
  2393. Status = WmipProcessGuidMaps( Logfiles, LogfileCount, Unicode );
  2394. if (Status != ERROR_SUCCESS) {
  2395. goto Cleanup;
  2396. }
  2397. //
  2398. // Set up storage
  2399. //
  2400. for (i=0; i < LogfileCount; i++) {
  2401. ULONG BufferSize, BufferCount;
  2402. ULONG SizeNeeded;
  2403. PUCHAR Space;
  2404. PTRACE_BUFFER_LIST_ENTRY Current;
  2405. pContext = (PTRACELOG_CONTEXT)Logfiles[i]->Context;
  2406. BufferSize = pContext->BufferSize;
  2407. BufferCount = pContext->BufferCount;
  2408. SizeNeeded = BufferCount * sizeof(TRACE_BUFFER_LIST_ENTRY);
  2409. pContext->BufferList = WmipMemCommit( NULL, SizeNeeded );
  2410. if (pContext->BufferList == NULL) {
  2411. Status = ERROR_OUTOFMEMORY;
  2412. goto Cleanup;
  2413. }
  2414. RtlZeroMemory(pContext->BufferList, SizeNeeded);
  2415. //
  2416. // Allocate Buffer Cache
  2417. //
  2418. SizeNeeded = MAX_TRACE_BUFFER_CACHE_SIZE * BufferSize;
  2419. Space = WmipMemCommit( NULL, SizeNeeded );
  2420. if (Space == NULL) {
  2421. Status = ERROR_OUTOFMEMORY;
  2422. goto Cleanup;
  2423. }
  2424. for (j=0; j<MAX_TRACE_BUFFER_CACHE_SIZE; j++) {
  2425. pContext->BufferCache[j].Index = -1;
  2426. pContext->BufferCache[j].Buffer = (PVOID)(Space + j * BufferSize);
  2427. }
  2428. pContext->BufferCacheSpace = Space;
  2429. Status = WmipBuildEventTable(pContext);
  2430. if (Status != ERROR_SUCCESS) {
  2431. goto Cleanup;
  2432. }
  2433. Current = pContext->Root;
  2434. if (Current != NULL) {
  2435. Logfiles[i]->CurrentTime = Current->Event.Header.TimeStamp.QuadPart;
  2436. }
  2437. else {
  2438. pContext->EndOfFile = TRUE;
  2439. }
  2440. }
  2441. //
  2442. // Make the Second Pass and get the events.
  2443. //
  2444. #ifdef DBG
  2445. WmipDumpCallbacks();
  2446. #endif
  2447. while (!Done) {
  2448. LONGLONG nextTimeStamp;
  2449. BOOL EventInRange;
  2450. //
  2451. // Check to see if end of file has been reached on all the
  2452. // files.
  2453. //
  2454. logfile = NULL;
  2455. nextTimeStamp = 0;
  2456. for (j=0; j < LogfileCount; j++) {
  2457. pContext = (PTRACELOG_CONTEXT)Logfiles[j]->Context;
  2458. if (pContext->EndOfFile)
  2459. continue;
  2460. if (nextTimeStamp == 0) {
  2461. nextTimeStamp = Logfiles[j]->CurrentTime;
  2462. logfile = Logfiles[j];
  2463. }
  2464. else if (nextTimeStamp > Logfiles[j]->CurrentTime) {
  2465. nextTimeStamp = Logfiles[j]->CurrentTime;
  2466. logfile = Logfiles[j];
  2467. }
  2468. }
  2469. if (logfile == NULL) {
  2470. break;
  2471. }
  2472. //
  2473. // if the Next event timestamp is not within the window of
  2474. // analysis, we do not fire the event callbacks.
  2475. //
  2476. EventInRange = TRUE;
  2477. if ((StartTime != 0) && (StartTime > nextTimeStamp))
  2478. EventInRange = FALSE;
  2479. if ((EndTime != 0) && (EndTime < nextTimeStamp))
  2480. EventInRange = FALSE;
  2481. //
  2482. // Now advance to next event.
  2483. //
  2484. Status = WmipAdvanceToNewEvent(logfile, EventInRange);
  2485. Done = (Status == ERROR_CANCELLED);
  2486. }
  2487. Cleanup:
  2488. for (i=0; i < LogfileCount; i++) {
  2489. pContext = (PTRACELOG_CONTEXT)Logfiles[i]->Context;
  2490. if (pContext != NULL) {
  2491. WmipCleanupTraceLog(pContext);
  2492. }
  2493. }
  2494. return Status;
  2495. }
  2496. ULONG
  2497. WmipCopyLogfileInfo(
  2498. PTRACELOG_CONTEXT HandleEntry,
  2499. PEVENT_TRACE_LOGFILEW Logfile,
  2500. ULONG Unicode
  2501. )
  2502. {
  2503. ULONG bufSize;
  2504. PWCHAR ws;
  2505. //
  2506. // Allocate LogfileName and LoggerName as well
  2507. //
  2508. RtlCopyMemory(&HandleEntry->Logfile,
  2509. Logfile,
  2510. sizeof(EVENT_TRACE_LOGFILEW));
  2511. HandleEntry->Logfile.LogFileName = NULL;
  2512. HandleEntry->Logfile.LoggerName = NULL;
  2513. if (Logfile->LogFileName != NULL) {
  2514. if (Unicode)
  2515. bufSize = (wcslen(Logfile->LogFileName) + 1) * sizeof(WCHAR);
  2516. else
  2517. bufSize = (strlen((PUCHAR)(Logfile->LogFileName)) + 1)
  2518. * sizeof(WCHAR);
  2519. ws = WmipAlloc( bufSize );
  2520. if (ws == NULL)
  2521. return ERROR_OUTOFMEMORY;
  2522. if (Unicode) {
  2523. wcscpy(ws, Logfile->LogFileName);
  2524. }
  2525. else {
  2526. MultiByteToWideChar(CP_ACP,
  2527. 0,
  2528. (LPCSTR)Logfile->LogFileName,
  2529. -1,
  2530. (LPWSTR)ws,
  2531. bufSize);
  2532. }
  2533. HandleEntry->Logfile.LogFileName = ws;
  2534. }
  2535. if (Logfile->LoggerName != NULL) {
  2536. if (Unicode)
  2537. bufSize = (wcslen(Logfile->LoggerName) + 1) * sizeof(WCHAR);
  2538. else
  2539. bufSize = (strlen((PUCHAR)(Logfile->LoggerName)) + 1)
  2540. * sizeof(WCHAR);
  2541. ws = WmipAlloc( bufSize );
  2542. if (ws == NULL)
  2543. return ERROR_OUTOFMEMORY;
  2544. if (Unicode)
  2545. wcscpy(ws, Logfile->LoggerName);
  2546. else {
  2547. MultiByteToWideChar(CP_ACP,
  2548. 0,
  2549. (LPCSTR)Logfile->LoggerName,
  2550. -1,
  2551. (LPWSTR)ws,
  2552. bufSize);
  2553. }
  2554. HandleEntry->Logfile.LoggerName = ws;
  2555. }
  2556. return ERROR_SUCCESS;
  2557. }
  2558. TRACEHANDLE
  2559. WMIAPI
  2560. OpenTraceA(
  2561. IN PEVENT_TRACE_LOGFILEA Logfile
  2562. )
  2563. /*++
  2564. Routine Description:
  2565. This is the Ansi version of the ProcessTracelogHeader routine.
  2566. Arguments:
  2567. LogFile Trace Input
  2568. Returned Value:
  2569. TraceHandle
  2570. --*/
  2571. {
  2572. ULONG status = ERROR_INVALID_PARAMETER;
  2573. PTRACELOG_CONTEXT HandleEntry = NULL;
  2574. TRACEHANDLE TraceHandle = (TRACEHANDLE)INVALID_HANDLE_VALUE;
  2575. WmipInitProcessHeap();
  2576. if (Logfile != NULL) {
  2577. HandleEntry = WmipAllocateTraceHandle();
  2578. if (HandleEntry == NULL) {
  2579. status = ERROR_OUTOFMEMORY;
  2580. }
  2581. else {
  2582. //
  2583. // Copy the LogFileStructure over. Converts strings to Unicode
  2584. //
  2585. TraceHandle = HandleEntry->TraceHandle;
  2586. try {
  2587. status = WmipCopyLogfileInfo(
  2588. HandleEntry,
  2589. (PEVENT_TRACE_LOGFILEW)Logfile,
  2590. FALSE
  2591. );
  2592. if (status == ERROR_SUCCESS) {
  2593. //
  2594. // For RealTime, handle is a place holder until ProcessTrace.
  2595. //
  2596. if ( (Logfile->LogFileMode & EVENT_TRACE_REAL_TIME_MODE)
  2597. != EVENT_TRACE_REAL_TIME_MODE ) {
  2598. status = WmipCreateGuidMapping();
  2599. if (status == ERROR_SUCCESS) {
  2600. status = WmipProcessLogHeader(
  2601. &HandleEntry->TraceHandle,
  2602. (PEVENT_TRACE_LOGFILEW*)&Logfile,
  2603. 1,
  2604. FALSE,
  2605. TRUE
  2606. );
  2607. }
  2608. }
  2609. }
  2610. }
  2611. except (EXCEPTION_EXECUTE_HANDLER) {
  2612. status = WmipNtStatusToDosError( GetExceptionCode() );
  2613. }
  2614. }
  2615. }
  2616. if ( (status != ERROR_SUCCESS) && (HandleEntry != NULL) ) {
  2617. WmipFreeTraceHandle(TraceHandle);
  2618. TraceHandle = (TRACEHANDLE)INVALID_HANDLE_VALUE;
  2619. }
  2620. WmipSetDosError(status);
  2621. return TraceHandle;
  2622. }
  2623. TRACEHANDLE
  2624. WMIAPI
  2625. OpenTraceW(
  2626. IN PEVENT_TRACE_LOGFILEW Logfile
  2627. )
  2628. /*++
  2629. Routine Description:
  2630. This routine processes a trace input and returns the tracelog header.
  2631. Only for logfiles. For realtime traces, the header may not be available.
  2632. Arguments:
  2633. Logfile Trace input.
  2634. Returned Value:
  2635. Pointer to Tracelog header.
  2636. --*/
  2637. {
  2638. ULONG status = ERROR_INVALID_PARAMETER;
  2639. PTRACELOG_CONTEXT HandleEntry = NULL;
  2640. TRACEHANDLE TraceHandle = (TRACEHANDLE)INVALID_HANDLE_VALUE;
  2641. WmipInitProcessHeap();
  2642. if (Logfile != NULL) {
  2643. HandleEntry = WmipAllocateTraceHandle();
  2644. if (HandleEntry == NULL) {
  2645. status = ERROR_OUTOFMEMORY;
  2646. }
  2647. else {
  2648. TraceHandle = HandleEntry->TraceHandle;
  2649. try {
  2650. status = WmipCopyLogfileInfo(
  2651. HandleEntry,
  2652. (PEVENT_TRACE_LOGFILEW)Logfile,
  2653. TRUE
  2654. );
  2655. if (status == ERROR_SUCCESS) {
  2656. if ( (Logfile->LogFileMode & EVENT_TRACE_REAL_TIME_MODE)
  2657. != EVENT_TRACE_REAL_TIME_MODE ) {
  2658. status = WmipCreateGuidMapping();
  2659. if (status == ERROR_SUCCESS) {
  2660. status = WmipProcessLogHeader(
  2661. &HandleEntry->TraceHandle,
  2662. (PEVENT_TRACE_LOGFILEW*)&Logfile,
  2663. 1,
  2664. TRUE,
  2665. TRUE
  2666. );
  2667. }
  2668. }
  2669. }
  2670. }
  2671. except (EXCEPTION_EXECUTE_HANDLER) {
  2672. status = WmipNtStatusToDosError( GetExceptionCode() );
  2673. }
  2674. }
  2675. }
  2676. if ( (status != ERROR_SUCCESS) && (HandleEntry != NULL) ) {
  2677. WmipFreeTraceHandle(TraceHandle);
  2678. TraceHandle = (TRACEHANDLE)INVALID_HANDLE_VALUE;
  2679. }
  2680. WmipSetDosError(status);
  2681. return TraceHandle;
  2682. }
  2683. ULONG
  2684. WMIAPI
  2685. ProcessTrace(
  2686. IN PTRACEHANDLE HandleArray,
  2687. IN ULONG HandleCount,
  2688. IN LPFILETIME StartTime,
  2689. IN LPFILETIME EndTime
  2690. )
  2691. {
  2692. PEVENT_TRACE_LOGFILEW Logfiles[MAXLOGGERS];
  2693. PLIST_ENTRY Head, Next;
  2694. PTRACELOG_CONTEXT pHandleEntry, pEntry;
  2695. ULONG i, Status;
  2696. LONGLONG sTime, eTime;
  2697. TRACEHANDLE SavedArray[MAXLOGGERS];
  2698. PEVENT_TRACE_LOGFILE logfile;
  2699. PEVENT_TRACE pEvent;
  2700. PTRACELOG_CONTEXT pContext;
  2701. PEVENT_TRACE_PROPERTIES Properties;
  2702. ULONG szProperties;
  2703. ULONG RealTimeDataFeed, LogFileDataFeed;
  2704. USHORT LoggerId;
  2705. TRACEHANDLE LoggerHandle = 0;
  2706. ULONG j;
  2707. BOOL Done = FALSE;
  2708. ACCESS_MASK DesiredAccess = TRACELOG_ACCESS_REALTIME;
  2709. WmipInitProcessHeap();
  2710. if ((HandleCount == 0) || (HandleCount >= MAXLOGGERS)) {
  2711. return ERROR_BAD_LENGTH;
  2712. }
  2713. if (HandleArray == NULL) {
  2714. return ERROR_INVALID_PARAMETER;
  2715. }
  2716. RtlZeroMemory(Logfiles, MAXLOGGERS*sizeof(PEVENT_TRACE_LOGFILEW) );
  2717. szProperties = sizeof(EVENT_TRACE_PROPERTIES) + 2 * MAXSTR * sizeof(WCHAR);
  2718. Properties = WmipAlloc(szProperties);
  2719. if (Properties == NULL) {
  2720. return ERROR_OUTOFMEMORY;
  2721. }
  2722. WmipEnterPMCritSection();
  2723. eTime = 0;
  2724. sTime = 0;
  2725. try {
  2726. if (StartTime != NULL)
  2727. sTime = *((PLONGLONG) StartTime);
  2728. if (EndTime != NULL)
  2729. eTime = *((PLONGLONG) EndTime);
  2730. if ((eTime != 0) && (eTime < sTime) ) {
  2731. WmipLeavePMCritSection();
  2732. Status = ERROR_INVALID_TIME;
  2733. goto Cleanup;
  2734. }
  2735. for (i=0; i<HandleCount; i++) {
  2736. SavedArray[i] = HandleArray[i];
  2737. if (SavedArray[i] == (TRACEHANDLE) INVALID_HANDLE_VALUE) {
  2738. WmipLeavePMCritSection();
  2739. Status = ERROR_INVALID_HANDLE;
  2740. goto Cleanup;
  2741. }
  2742. }
  2743. for (i=0; i< HandleCount; i++) {
  2744. pHandleEntry = NULL;
  2745. Head = TraceHandleListHeadPtr;
  2746. if (Head != NULL) {
  2747. Next = Head->Flink;
  2748. while (Next != Head) {
  2749. pEntry = CONTAINING_RECORD(Next,
  2750. TRACELOG_CONTEXT,
  2751. Entry);
  2752. Next = Next->Flink;
  2753. if (SavedArray[i] == pEntry->TraceHandle) {
  2754. if (pEntry->fProcessed == FALSE) {
  2755. pHandleEntry = pEntry;
  2756. pHandleEntry->fProcessed = TRUE;
  2757. }
  2758. break;
  2759. }
  2760. }
  2761. }
  2762. if (pHandleEntry == NULL) {
  2763. Status = ERROR_INVALID_HANDLE;
  2764. WmipLeavePMCritSection();
  2765. goto Cleanup;
  2766. }
  2767. Logfiles[i] = &pHandleEntry->Logfile;
  2768. }
  2769. WmipLeavePMCritSection();
  2770. //
  2771. // Scan the Logfiles list and decide it's realtime or
  2772. // Logfile Proceessing.
  2773. //
  2774. for (i=0; i < HandleCount; i++) {
  2775. RealTimeDataFeed = FALSE;
  2776. LogFileDataFeed = FALSE;
  2777. //
  2778. // Check to see if this is a RealTime Datafeed
  2779. //
  2780. if (Logfiles[i]->LogFileMode & EVENT_TRACE_REAL_TIME_MODE) {
  2781. if (Logfiles[i]->LoggerName == NULL) {
  2782. Status = WmipSetDosError(ERROR_INVALID_NAME);
  2783. goto Cleanup;
  2784. }
  2785. //
  2786. // Using the LoggerName, Query the Logger to determine
  2787. // whether this is a Kernel or Usermode realtime logger.
  2788. //
  2789. RtlZeroMemory(Properties, szProperties);
  2790. Properties->Wnode.BufferSize = szProperties;
  2791. Status = ControlTraceW(LoggerHandle,
  2792. (LPWSTR)Logfiles[i]->LoggerName,
  2793. Properties,
  2794. EVENT_TRACE_CONTROL_QUERY);
  2795. if (Status != ERROR_SUCCESS) {
  2796. goto Cleanup;
  2797. }
  2798. if (!(Properties->LogFileMode & EVENT_TRACE_REAL_TIME_MODE)) {
  2799. Status = ERROR_WMI_INSTANCE_NOT_FOUND;
  2800. goto Cleanup;
  2801. }
  2802. Logfiles[i]->IsKernelTrace =
  2803. IsEqualGUID(&Properties->Wnode.Guid, &SystemTraceControlGuid);
  2804. LoggerId = WmiGetLoggerId(Properties->Wnode.HistoricalContext);
  2805. if (LoggerId == KERNEL_LOGGER_ID)
  2806. LoggerId = 0;
  2807. Logfiles[i]->Filled = LoggerId; // Temporarily stash it away
  2808. Logfiles[i]->LogfileHeader.LogInstanceGuid = Properties->Wnode.Guid;
  2809. //
  2810. // If the Logger is using UsePerfClock for TimeStamps, make a reference
  2811. // timestamp now.
  2812. //
  2813. Logfiles[i]->LogfileHeader.ReservedFlags = Properties->Wnode.ClientContext;
  2814. //
  2815. // Save the BuffferSize for Realtime Buffer Pool Allocation
  2816. //
  2817. Logfiles[i]->BufferSize = Properties->BufferSize * 1024;
  2818. //
  2819. // This is the place to do security check on this Guid.
  2820. //
  2821. Status = WmipCheckGuidAccess( &Properties->Wnode.Guid,
  2822. DesiredAccess );
  2823. if (Status != ERROR_SUCCESS) {
  2824. goto Cleanup;
  2825. }
  2826. RealTimeDataFeed = TRUE;
  2827. }
  2828. //
  2829. // Check to see if this is a Logfile datafeed.
  2830. //
  2831. if (!(Logfiles[i]->LogFileMode & EVENT_TRACE_REAL_TIME_MODE)) {
  2832. if (Logfiles[i]->LogFileName == NULL) {
  2833. Status = WmipSetDosError(ERROR_BAD_PATHNAME);
  2834. goto Cleanup;
  2835. }
  2836. if ( wcslen((LPWSTR)Logfiles[i]->LogFileName) <= 0 ) {
  2837. Status = WmipSetDosError(ERROR_BAD_PATHNAME);
  2838. goto Cleanup;
  2839. }
  2840. LogFileDataFeed = TRUE;
  2841. }
  2842. //
  2843. // We don't support both RealTimeFeed and LogFileDataFeed.
  2844. //
  2845. if (RealTimeDataFeed && LogFileDataFeed) {
  2846. Status = WmipSetDosError(ERROR_INVALID_PARAMETER);
  2847. goto Cleanup;
  2848. }
  2849. }
  2850. if (LogFileDataFeed) {
  2851. Status = WmipProcessTraceLog(&SavedArray[0], Logfiles,
  2852. HandleCount,
  2853. sTime,
  2854. eTime,
  2855. TRUE);
  2856. }
  2857. else {
  2858. Status = WmipProcessRealTimeTraces(&SavedArray[0], Logfiles,
  2859. HandleCount,
  2860. sTime,
  2861. eTime,
  2862. TRUE);
  2863. }
  2864. } except (EXCEPTION_EXECUTE_HANDLER) {
  2865. Status = GetExceptionCode();
  2866. #ifdef DBG
  2867. WmipDebugPrint(("TRACE: WmipProcessTraceLog threw exception %X\n",
  2868. Status));
  2869. #endif
  2870. Status = WmipSetDosError(WmipNtStatusToDosError(Status));
  2871. }
  2872. try {
  2873. WmipEnterPMCritSection();
  2874. for (i=0; i< HandleCount; i++) {
  2875. pHandleEntry = NULL;
  2876. Head = TraceHandleListHeadPtr;
  2877. WmipAssert(Head);
  2878. Next = Head->Flink;
  2879. while (Next != Head) {
  2880. pEntry = CONTAINING_RECORD(Next, TRACELOG_CONTEXT, Entry);
  2881. Next = Next->Flink;
  2882. if (SavedArray[i] == pEntry->TraceHandle) {
  2883. pEntry->fProcessed = FALSE;
  2884. break;
  2885. }
  2886. }
  2887. }
  2888. WmipLeavePMCritSection();
  2889. } except (EXCEPTION_EXECUTE_HANDLER) {
  2890. Status = GetExceptionCode();
  2891. #ifdef DBG
  2892. WmipDebugPrint(("TRACE: WmipProcessTraceLog threw exception %X\n",
  2893. Status));
  2894. #endif
  2895. Status = WmipSetDosError(WmipNtStatusToDosError(Status));
  2896. }
  2897. Cleanup:
  2898. WmipFree(Properties);
  2899. return Status;
  2900. }
  2901. ULONG
  2902. WMIAPI
  2903. CloseTrace(
  2904. IN TRACEHANDLE TraceHandle
  2905. )
  2906. {
  2907. WmipInitProcessHeap();
  2908. if ((TraceHandle == 0) ||
  2909. (TraceHandle == (TRACEHANDLE)INVALID_HANDLE_VALUE))
  2910. return ERROR_INVALID_HANDLE;
  2911. return WmipFreeTraceHandle(TraceHandle);
  2912. }
  2913. VOID
  2914. WmipGuidMapCallback(
  2915. PLIST_ENTRY GuidMapListHeadPtr,
  2916. PEVENT_TRACE pEvent
  2917. )
  2918. {
  2919. PTRACEGUIDMAP GuidMap;
  2920. WmipInitProcessHeap();
  2921. if (pEvent == NULL)
  2922. return;
  2923. GuidMap = (PTRACEGUIDMAP) pEvent->MofData;
  2924. if (GuidMap != NULL) {
  2925. WmipAddGuidHandleToGuidMapList(GuidMapListHeadPtr, GuidMap->GuidMapHandle, &GuidMap->Guid);
  2926. }
  2927. }
  2928. void
  2929. WmipCleanupTraceLog(
  2930. PTRACELOG_CONTEXT pContext
  2931. )
  2932. {
  2933. ULONG Size;
  2934. //
  2935. // Free up the realtime context arrays and buffers
  2936. //
  2937. WmipEnterPMCritSection();
  2938. if (pContext->IsRealTime) {
  2939. if (pContext->Root != NULL) {
  2940. WmipFree(pContext->Root);
  2941. }
  2942. WmipFreeRealTimeContext(pContext->RealTimeCxt);
  2943. }
  2944. else {
  2945. if (pContext->Handle != NULL) {
  2946. NtClose(pContext->Handle);
  2947. pContext->Handle = NULL;
  2948. }
  2949. }
  2950. if (pContext->BufferList != NULL) {
  2951. WmipMemFree(pContext->BufferList);
  2952. }
  2953. if (pContext->BufferCacheSpace != NULL) {
  2954. WmipMemFree(pContext->BufferCacheSpace);
  2955. }
  2956. WmipCleanupGuidMapList(&pContext->GuidMapListHead);
  2957. //
  2958. // The following fields need to be reset since the caller
  2959. // may call ProcessTrace again with the same handle
  2960. //
  2961. Size = sizeof(TRACELOG_CONTEXT) - FIELD_OFFSET(TRACELOG_CONTEXT, fProcessed);
  2962. RtlZeroMemory(&pContext->fProcessed, Size);
  2963. InitializeListHead (&pContext->GuidMapListHead);
  2964. WmipLeavePMCritSection();
  2965. //
  2966. // TODO: We need to use a ref count mechanism before deleting the
  2967. // EventMapList and CallbackLists
  2968. //
  2969. // if (EventMapList != NULL) {
  2970. // HeapFree(GetProcessHeap(), 0, EventMapList);
  2971. // EventMapList = NULL;
  2972. // }
  2973. // WmipFreeCallbackList();
  2974. }
  2975. ULONG
  2976. WMIAPI
  2977. WmiGetFirstTraceOffset(
  2978. IN PWMIBUFFERINFO BufferInfo
  2979. )
  2980. /*++
  2981. Routine Description:
  2982. This is the private API for buffer walking for cluster/
  2983. debugger support.
  2984. Returns the Offset to the first event.
  2985. Arguments:
  2986. Returned Value:
  2987. Status code
  2988. --*/
  2989. {
  2990. PVOID pBuffer;
  2991. PWMI_BUFFER_HEADER pHeader;
  2992. PLONG LastByte;
  2993. if (BufferInfo == NULL) {
  2994. return 0;
  2995. }
  2996. pBuffer = BufferInfo->Buffer;
  2997. if (pBuffer == NULL) {
  2998. return 0;
  2999. }
  3000. pHeader = (PWMI_BUFFER_HEADER) pBuffer;
  3001. switch(BufferInfo->BufferSource) {
  3002. case WMIBS_CURRENT_LIST:
  3003. {
  3004. // TODO: Fix GlennP's debugger problem in 2195
  3005. //
  3006. // ULONG lMask = ~((ULONG)0);
  3007. pHeader->Wnode.BufferSize = BufferInfo->BufferSize;
  3008. pHeader->ClientContext.Alignment = (UCHAR)BufferInfo->Alignment;
  3009. // if (BufferInfo->ProcessorNumber < lMask) {
  3010. // pHeader->ClientContext.ProcessorNumber = (UCHAR)BufferInfo->ProcessorNumber;
  3011. // }
  3012. pHeader->Offset = pHeader->CurrentOffset;
  3013. break;
  3014. }
  3015. case WMIBS_FREE_LIST:
  3016. {
  3017. pHeader->Offset = pHeader->CurrentOffset;
  3018. if (pHeader->SavedOffset > 0)
  3019. pHeader->Offset = pHeader->SavedOffset;
  3020. if (pHeader->Offset == 0) {
  3021. pHeader->Offset = sizeof(WMI_BUFFER_HEADER);
  3022. }
  3023. pHeader->Wnode.BufferSize = BufferInfo->BufferSize;
  3024. break;
  3025. }
  3026. case WMIBS_TRANSITION_LIST:
  3027. {
  3028. if (pHeader->SavedOffset > 0) {
  3029. pHeader->Offset = pHeader->SavedOffset;
  3030. }
  3031. break;
  3032. }
  3033. case WMIBS_FLUSH_LIST:
  3034. {
  3035. if (pHeader->SavedOffset > 0) {
  3036. pHeader->Offset = pHeader->SavedOffset;
  3037. }
  3038. pHeader->Wnode.BufferSize = BufferInfo->BufferSize;
  3039. break;
  3040. }
  3041. case WMIBS_LOG_FILE:
  3042. {
  3043. break;
  3044. }
  3045. }
  3046. if (BufferInfo->BufferSource != WMIBS_LOG_FILE) {
  3047. LastByte = (PLONG) ((PUCHAR)pHeader+ pHeader->Offset);
  3048. if (pHeader->Offset <= (BufferInfo->BufferSize - sizeof(ULONG)) ) {
  3049. *LastByte = -1;
  3050. }
  3051. }
  3052. return sizeof(WMI_BUFFER_HEADER);
  3053. }
  3054. ULONG
  3055. WmipConvertEnumToTraceType(
  3056. WMI_HEADER_TYPE eTraceType
  3057. )
  3058. {
  3059. switch(eTraceType) {
  3060. case WMIHT_SYSTEM32:
  3061. return TRACE_HEADER_TYPE_SYSTEM32;
  3062. case WMIHT_SYSTEM64:
  3063. return TRACE_HEADER_TYPE_SYSTEM64;
  3064. case WMIHT_EVENT_TRACE:
  3065. return TRACE_HEADER_TYPE_FULL_HEADER;
  3066. case WMIHT_EVENT_INSTANCE:
  3067. return TRACE_HEADER_TYPE_INSTANCE;
  3068. case WMIHT_TIMED:
  3069. return TRACE_HEADER_TYPE_TIMED;
  3070. case WMIHT_ULONG32:
  3071. return TRACE_HEADER_TYPE_ULONG32;
  3072. case WMIHT_WNODE:
  3073. return TRACE_HEADER_TYPE_WNODE_HEADER;
  3074. case WMIHT_MESSAGE:
  3075. return TRACE_HEADER_TYPE_MESSAGE;
  3076. case WMIHT_PERFINFO32:
  3077. return TRACE_HEADER_TYPE_PERFINFO32;
  3078. case WMIHT_PERFINFO64:
  3079. return TRACE_HEADER_TYPE_PERFINFO64;
  3080. default:
  3081. return 0;
  3082. }
  3083. }
  3084. WMI_HEADER_TYPE
  3085. WmipConvertTraceTypeToEnum(
  3086. ULONG TraceType
  3087. )
  3088. {
  3089. switch(TraceType) {
  3090. case TRACE_HEADER_TYPE_SYSTEM32:
  3091. return WMIHT_SYSTEM32;
  3092. case TRACE_HEADER_TYPE_SYSTEM64:
  3093. return WMIHT_SYSTEM64;
  3094. case TRACE_HEADER_TYPE_FULL_HEADER:
  3095. return WMIHT_EVENT_TRACE;
  3096. case TRACE_HEADER_TYPE_INSTANCE:
  3097. return WMIHT_EVENT_INSTANCE;
  3098. case TRACE_HEADER_TYPE_TIMED:
  3099. return WMIHT_TIMED;
  3100. case TRACE_HEADER_TYPE_ULONG32:
  3101. return WMIHT_ULONG32;
  3102. case TRACE_HEADER_TYPE_WNODE_HEADER:
  3103. return WMIHT_WNODE;
  3104. case TRACE_HEADER_TYPE_MESSAGE:
  3105. return WMIHT_MESSAGE;
  3106. case TRACE_HEADER_TYPE_PERFINFO32:
  3107. return WMIHT_PERFINFO32;
  3108. case TRACE_HEADER_TYPE_PERFINFO64:
  3109. return WMIHT_PERFINFO64;
  3110. default:
  3111. return WMIHT_NONE;
  3112. }
  3113. }
  3114. WMI_HEADER_TYPE
  3115. WMIAPI
  3116. WmiGetTraceHeader(
  3117. IN PVOID LogBuffer,
  3118. IN ULONG Offset,
  3119. OUT ULONG *Size
  3120. )
  3121. {
  3122. ULONG Status = ERROR_SUCCESS;
  3123. ULONG TraceType;
  3124. try {
  3125. TraceType = WmipGetNextEventOffsetType(
  3126. (PUCHAR)LogBuffer,
  3127. Offset,
  3128. Size
  3129. );
  3130. return WmipConvertTraceTypeToEnum(TraceType);
  3131. } except (EXCEPTION_EXECUTE_HANDLER) {
  3132. Status = GetExceptionCode();
  3133. #ifdef DBG
  3134. WmipDebugPrint(("TRACE: WmiGetTraceHeader threw exception %X\n",
  3135. Status));
  3136. #endif
  3137. Status = WmipSetDosError(WmipNtStatusToDosError(Status));
  3138. }
  3139. return 0;
  3140. }
  3141. ULONG
  3142. WMIAPI
  3143. WmiParseTraceEvent(
  3144. IN PVOID LogBuffer,
  3145. IN ULONG Offset,
  3146. IN WMI_HEADER_TYPE HeaderType,
  3147. IN OUT PVOID EventInfo,
  3148. IN ULONG EventInfoSize
  3149. )
  3150. {
  3151. return WmipParseTraceEvent(NULL, LogBuffer, Offset, HeaderType, EventInfo, EventInfoSize);
  3152. }
  3153. ULONG
  3154. WmipParseTraceEvent(
  3155. IN PTRACELOG_CONTEXT pContext,
  3156. IN PVOID LogBuffer,
  3157. IN ULONG Offset,
  3158. IN WMI_HEADER_TYPE HeaderType,
  3159. IN OUT PVOID EventInfo,
  3160. IN ULONG EventInfoSize
  3161. )
  3162. {
  3163. PWMI_BUFFER_HEADER Header = (PWMI_BUFFER_HEADER)LogBuffer;
  3164. ULONG Status = ERROR_SUCCESS;
  3165. PVOID pEvent;
  3166. if ( (LogBuffer == NULL) ||
  3167. (EventInfo == NULL) ||
  3168. (EventInfoSize < sizeof(EVENT_TRACE_HEADER)) )
  3169. {
  3170. return (ERROR_INVALID_PARAMETER);
  3171. }
  3172. Status = WmipCreateGuidMapping();
  3173. if (Status != ERROR_SUCCESS) {
  3174. return Status;
  3175. }
  3176. try {
  3177. RtlZeroMemory(EventInfo, sizeof(EVENT_TRACE));
  3178. pEvent = (void*) ((PUCHAR)LogBuffer + Offset);
  3179. WmipCopyCurrentEvent(pContext,
  3180. pEvent,
  3181. EventInfo,
  3182. WmipConvertEnumToTraceType(HeaderType),
  3183. (PWMI_BUFFER_HEADER)LogBuffer
  3184. );
  3185. ( (PEVENT_TRACE)EventInfo)->ClientContext = Header->Wnode.ClientContext;
  3186. } except (EXCEPTION_EXECUTE_HANDLER) {
  3187. Status = GetExceptionCode();
  3188. #ifdef DBG
  3189. WmipDebugPrint(("TRACE: WmipParseTraceEvent threw exception %X\n",
  3190. Status));
  3191. #endif
  3192. Status = WmipSetDosError(WmipNtStatusToDosError(Status));
  3193. }
  3194. return Status;
  3195. }
  3196. //
  3197. // RealTime Routines
  3198. //
  3199. PVOID
  3200. WmipAllocTraceBuffer(
  3201. PTRACELOG_REALTIME_CONTEXT RTCxt,
  3202. ULONG BufferSize
  3203. )
  3204. {
  3205. PVOID Buffer = NULL;
  3206. PTRACE_BUFFER_HEADER Header;
  3207. PLIST_ENTRY Head, Next;
  3208. PTRACERT_BUFFER_LIST_ENTRY ListEntry;
  3209. PTRACE_BUFFER_SPACE WmipTraceBufferSpace;
  3210. WmipEnterPMCritSection();
  3211. WmipTraceBufferSpace = RTCxt->WmipTraceBufferSpace;
  3212. Head = &WmipTraceBufferSpace->FreeListHead;
  3213. Next = Head->Flink;
  3214. while (Head != Next) {
  3215. ListEntry = CONTAINING_RECORD(Next, TRACERT_BUFFER_LIST_ENTRY, Entry);
  3216. Next = Next->Flink;
  3217. if (ListEntry->Size == BufferSize) {
  3218. goto foundList;
  3219. }
  3220. }
  3221. //
  3222. // No list for this bufferSize was found. So go Ahead and allocate one.
  3223. //
  3224. ListEntry = WmipAlloc(sizeof(TRACERT_BUFFER_LIST_ENTRY));
  3225. if (ListEntry == NULL) {
  3226. WmipSetDosError(ERROR_OUTOFMEMORY);
  3227. WmipLeavePMCritSection();
  3228. return NULL;
  3229. }
  3230. RtlZeroMemory(ListEntry, sizeof(TRACERT_BUFFER_LIST_ENTRY));
  3231. ListEntry->Size = BufferSize;
  3232. InitializeListHead(&ListEntry->BufferListHead);
  3233. InsertHeadList(&WmipTraceBufferSpace->FreeListHead, &ListEntry->Entry);
  3234. foundList:
  3235. //
  3236. // Now look for a free buffer in this list
  3237. //
  3238. Head = &ListEntry->BufferListHead;
  3239. Next = Head->Flink;
  3240. while (Head != Next) {
  3241. Header = CONTAINING_RECORD( Next, TRACE_BUFFER_HEADER, Entry );
  3242. if (((PWNODE_HEADER)Header)->BufferSize == BufferSize) {
  3243. RemoveEntryList(&Header->Entry);
  3244. Buffer = (PVOID)Header;
  3245. break;
  3246. }
  3247. Next = Next->Flink;
  3248. }
  3249. WmipLeavePMCritSection();
  3250. //
  3251. // If No Free Buffers are found we try to allocate one and return.
  3252. //
  3253. if (Buffer == NULL) {
  3254. PVOID Space;
  3255. ULONG SizeLeft = WmipTraceBufferSpace->Reserved -
  3256. WmipTraceBufferSpace->Committed;
  3257. if (SizeLeft < BufferSize) {
  3258. WmipSetDosError(ERROR_OUTOFMEMORY);
  3259. return NULL;
  3260. }
  3261. Space = (PVOID)( (PCHAR)WmipTraceBufferSpace->Space +
  3262. WmipTraceBufferSpace->Committed );
  3263. Buffer = WmipMemCommit( Space, BufferSize );
  3264. if (Buffer != NULL) {
  3265. WmipTraceBufferSpace->Committed += BufferSize;
  3266. }
  3267. }
  3268. return (Buffer);
  3269. }
  3270. VOID
  3271. WmipFreeTraceBuffer(
  3272. PTRACELOG_REALTIME_CONTEXT RTCxt,
  3273. PVOID Buffer
  3274. )
  3275. {
  3276. PTRACE_BUFFER_HEADER Header = (PTRACE_BUFFER_HEADER)Buffer;
  3277. PLIST_ENTRY Head, Next;
  3278. ULONG BufferSize = Header->Wnode.BufferSize;
  3279. PTRACERT_BUFFER_LIST_ENTRY ListEntry;
  3280. PLIST_ENTRY BufferList = NULL;
  3281. PTRACE_BUFFER_SPACE WmipTraceBufferSpace;
  3282. WmipEnterPMCritSection();
  3283. WmipTraceBufferSpace = RTCxt->WmipTraceBufferSpace;
  3284. Head = &WmipTraceBufferSpace->FreeListHead;
  3285. Next = Head->Flink;
  3286. while (Head != Next) {
  3287. ListEntry = CONTAINING_RECORD(Next, TRACERT_BUFFER_LIST_ENTRY, Entry);
  3288. Next = Next->Flink;
  3289. if (ListEntry->Size == BufferSize) {
  3290. BufferList = &ListEntry->BufferListHead;
  3291. break;
  3292. }
  3293. }
  3294. if (BufferList != NULL) {
  3295. InsertHeadList(BufferList, &Header->Entry);
  3296. }
  3297. else {
  3298. // We shoule not get here. If we do the buffer->Size is
  3299. // Corrupted.
  3300. WmipAssert(BufferList == NULL);
  3301. }
  3302. WmipLeavePMCritSection();
  3303. }
  3304. //
  3305. // TODO: If two threads called processtrace for the same RT stream, how can we fire
  3306. // two callbacks
  3307. //
  3308. ULONG
  3309. WmipRealTimeCallback(
  3310. IN PWNODE_HEADER Wnode,
  3311. IN ULONG_PTR RTContext //LogFileIndex
  3312. )
  3313. /*++
  3314. Routine Description:
  3315. This routine is called when a real time buffer becomes available.
  3316. The buffer delivered by WMI is copied to a local pool of ring buffers.
  3317. Each realtime data feed maintains its own pool of ring buffers and the
  3318. LogFileIndex passed back via the Wnode (ProviderId field)
  3319. identifies the stream to which the buffer is destined.
  3320. Arguments:
  3321. Wnode Buffer
  3322. LogFileIndex Index of the Input stream from which this buffer came.
  3323. Returned Value:
  3324. Status Code.
  3325. --*/
  3326. {
  3327. ULONG index;
  3328. PTRACELOG_REALTIME_CONTEXT Context = (PTRACELOG_REALTIME_CONTEXT) RTContext;
  3329. PWNODE_HEADER pHeader;
  3330. PWMI_CLIENT_CONTEXT ClientContext;
  3331. //
  3332. // Assumes that the number of LogFiles is less than the MAXLOGGERS.
  3333. //
  3334. // Get the LogFileIndex to which this buffer is destined through the
  3335. // Logger Historical Context.
  3336. ClientContext = (PWMI_CLIENT_CONTEXT)&Wnode->ClientContext;
  3337. //
  3338. // If we can't use this buffer for whatever reason, we return and
  3339. // the return code is always ERROR_SUCCESS.
  3340. //
  3341. //
  3342. // Circular FIFO queue of MAXBUFFERS to hold the buffers.
  3343. // Producer to Fill it and Consumer to Null it.
  3344. //
  3345. index = (Context->BuffersProduced % MAXBUFFERS);
  3346. if (Context->RealTimeBufferPool[index] == NULL) { //Empty slot found.
  3347. pHeader = (PWNODE_HEADER) WmipAllocTraceBuffer(Context, Wnode->BufferSize);
  3348. if (pHeader == NULL) {
  3349. return ERROR_SUCCESS;
  3350. }
  3351. RtlCopyMemory(pHeader, Wnode, Wnode->BufferSize); // One more copy!?
  3352. Context->RealTimeBufferPool[index] = pHeader;
  3353. Context->BuffersProduced++;
  3354. NtSetEvent(Context->MoreDataEvent, NULL); //Signal the dc there's more data.
  3355. }
  3356. else { // No Empty Slots found.
  3357. Context->BufferOverflow++; // Simply let the buffer go.
  3358. }
  3359. //
  3360. // wmi service maintains only the Delta buffersLost since the last time
  3361. // it was reported. The Count is zeroed once it is reported in a delivered
  3362. // buffer. This means I can add it directly.
  3363. //
  3364. Context->BufferOverflow += Wnode->CountLost;
  3365. return ERROR_SUCCESS;
  3366. }
  3367. ULONG
  3368. WmipSetupRealTimeContext(
  3369. PTRACEHANDLE HandleArray,
  3370. PEVENT_TRACE_LOGFILEW *Logfiles,
  3371. ULONG LogfileCount
  3372. )
  3373. /*++
  3374. Routine Description:
  3375. This routine sets up the context to process real time buffers.
  3376. The real time buffers delivered will be copied and kept in a circular
  3377. buffer pool until the ProcessTracelog routine can consume it.
  3378. Arguments:
  3379. LogFile Array of Logfiles being processed.
  3380. LogFileCount Number of Logfiles in the Array.
  3381. Returned Value:
  3382. Status Code.
  3383. --*/
  3384. {
  3385. ULONG i;
  3386. ULONG Status;
  3387. USHORT LoggerId;
  3388. ULONG TotalBufferSize = 0;
  3389. SYSTEM_BASIC_INFORMATION SystemInfo;
  3390. ULONG RealTimeRegistered = FALSE;
  3391. Status = WmipCreateGuidMapping();
  3392. if (Status != ERROR_SUCCESS) {
  3393. return Status;
  3394. }
  3395. for (i=0; i < LogfileCount; i++) {
  3396. if (Logfiles[i]->LogFileMode & EVENT_TRACE_REAL_TIME_MODE) {
  3397. TotalBufferSize += Logfiles[i]->BufferSize; // * SystemInfo.NumberOfProcessors;
  3398. }
  3399. }
  3400. if (TotalBufferSize == 0)
  3401. TotalBufferSize = DEFAULT_REALTIME_BUFFER_SIZE;
  3402. //
  3403. // Initialize the real time data feed Structures.
  3404. //
  3405. for (i=0; i < LogfileCount; i++) {
  3406. PTRACELOG_REALTIME_CONTEXT RTCxt;
  3407. PTRACELOG_CONTEXT pContext;
  3408. PTRACE_BUFFER_LIST_ENTRY pListEntry;
  3409. LARGE_INTEGER Frequency;
  3410. ULONGLONG Counter = 0;
  3411. if (Logfiles[i]->LogFileMode & EVENT_TRACE_REAL_TIME_MODE) {
  3412. pContext = WmipLookupTraceHandle(HandleArray[i]);
  3413. if (pContext == NULL) {
  3414. return WmipSetDosError(ERROR_OUTOFMEMORY);
  3415. }
  3416. pContext->IsRealTime = TRUE;
  3417. pContext->Handle = NULL;
  3418. Logfiles[i]->Context = pContext;
  3419. Logfiles[i]->BuffersRead = 0;
  3420. pContext->EndOfFile = TRUE;
  3421. //
  3422. // Save the flags from OpenTrace at this time before the first
  3423. // buffer callback which will erase it.
  3424. //
  3425. pContext->ConversionFlags = Logfiles[i]->LogfileHeader.ReservedFlags;
  3426. pContext->UsePerfClock = Logfiles[i]->LogfileHeader.ReservedFlags;
  3427. //
  3428. // If the conversion flags are set, adjust UsePerfClock accordingly.
  3429. //
  3430. if (pContext->ConversionFlags & EVENT_TRACE_USE_RAWTIMESTAMP ) {
  3431. pContext->UsePerfClock = EVENT_TRACE_CLOCK_RAW;
  3432. }
  3433. //
  3434. // Fill in the StartTime, Frequency and StartPerfClock fields
  3435. //
  3436. Status = NtQueryPerformanceCounter((PLARGE_INTEGER)&Counter,
  3437. &Frequency);
  3438. pContext->StartPerfClock.QuadPart = Counter;
  3439. pContext->PerfFreq.QuadPart = Frequency.QuadPart;
  3440. pContext->StartTime.QuadPart = WmipGetSystemTime();
  3441. RTCxt = (PTRACELOG_REALTIME_CONTEXT)WmipAlloc(
  3442. sizeof(TRACELOG_REALTIME_CONTEXT));
  3443. if (RTCxt == NULL) {
  3444. return WmipSetDosError(ERROR_OUTOFMEMORY);
  3445. }
  3446. RtlZeroMemory(RTCxt, sizeof(TRACELOG_REALTIME_CONTEXT));
  3447. RTCxt->MoreDataEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  3448. if (RTCxt->MoreDataEvent == NULL) {
  3449. return WmipSetDosError(ERROR_OBJECT_NOT_FOUND);
  3450. }
  3451. //
  3452. // Save the RTCxt in a global pContext array so that the
  3453. // notification callback from WMI can get at it through the
  3454. // logfile index i.
  3455. //
  3456. LoggerId = (USHORT)Logfiles[i]->Filled; // get the stashed LoggerId.
  3457. pContext->LoggerId = LoggerId;
  3458. pContext->RealTimeCxt = RTCxt;
  3459. RTCxt->InstanceGuid = Logfiles[i]->LogfileHeader.LogInstanceGuid;
  3460. //
  3461. // Allocate the buffer space to receive the ral time buffers
  3462. //
  3463. if ( !RealTimeRegistered) {
  3464. ULONG SizeReserved;
  3465. PVOID BufferSpace;
  3466. //
  3467. // Right before starting to receive the realtime buffers
  3468. // get a dump of the GuidMaps if any.
  3469. ///
  3470. WmipDumpGuidMaps(NULL, &pContext->GuidMapListHead, TRUE);
  3471. RealTimeRegistered = TRUE;
  3472. RTCxt->WmipTraceBufferSpace = (PTRACE_BUFFER_SPACE)WmipAlloc(
  3473. sizeof(TRACE_BUFFER_SPACE));
  3474. if (RTCxt->WmipTraceBufferSpace == NULL) {
  3475. return ERROR_OUTOFMEMORY;
  3476. }
  3477. RtlZeroMemory(RTCxt->WmipTraceBufferSpace, sizeof(TRACE_BUFFER_SPACE));
  3478. InitializeListHead(&RTCxt->WmipTraceBufferSpace->FreeListHead);
  3479. SizeReserved = MAXBUFFERS *
  3480. TotalBufferSize;
  3481. BufferSpace = WmipMemReserve( SizeReserved );
  3482. if (BufferSpace == NULL) {
  3483. return ERROR_OUTOFMEMORY;
  3484. }
  3485. RTCxt->WmipTraceBufferSpace->Reserved = SizeReserved;
  3486. RTCxt->WmipTraceBufferSpace->Space = BufferSpace;
  3487. }
  3488. //
  3489. // For Every Logger Stream we need to register with WMI
  3490. // for buffer notification with its Security Guid.
  3491. //
  3492. Status = WmiNotificationRegistration(
  3493. (const LPGUID) &RTCxt->InstanceGuid,
  3494. TRUE,
  3495. WmipRealTimeCallback,
  3496. (ULONG_PTR)RTCxt,
  3497. NOTIFICATION_CALLBACK_DIRECT
  3498. );
  3499. if (Status != ERROR_SUCCESS) {
  3500. return Status;
  3501. }
  3502. //
  3503. // Allocate Room to process one event
  3504. //
  3505. pListEntry = (PTRACE_BUFFER_LIST_ENTRY) WmipAlloc( sizeof(TRACE_BUFFER_LIST_ENTRY) );
  3506. if (pListEntry == NULL) {
  3507. return ERROR_OUTOFMEMORY;
  3508. }
  3509. RtlZeroMemory(pListEntry, sizeof(TRACE_BUFFER_LIST_ENTRY) );
  3510. pContext->Root = pListEntry;
  3511. }
  3512. }
  3513. return ERROR_SUCCESS;
  3514. }
  3515. ULONG
  3516. WmipLookforRealTimeBuffers(
  3517. PEVENT_TRACE_LOGFILEW logfile
  3518. )
  3519. /*++
  3520. Routine Description:
  3521. This routine checks to see if there are any real time buffers
  3522. ready for consumption. If so, it sets up the CurrentBuffer and
  3523. the CurrentEvent for this logfile stream. If no buffers are available
  3524. simply sets the EndOfFile to be true.
  3525. Arguments:
  3526. logfile Current Logfile being processed.
  3527. Returned Value:
  3528. ERROR_SUCCESS Successfully moved to the next event.
  3529. --*/
  3530. {
  3531. ULONG index;
  3532. ULONG BuffersRead;
  3533. PVOID pBuffer;
  3534. PEVENT_TRACE pEvent;
  3535. PTRACELOG_CONTEXT pContext;
  3536. PTRACELOG_REALTIME_CONTEXT RTCxt;
  3537. PWMI_BUFFER_HEADER pHeader;
  3538. WMI_HEADER_TYPE HeaderType = WMIHT_NONE;
  3539. ULONG Size;
  3540. ULONG Offset;
  3541. ULONG Status;
  3542. if (logfile == NULL) {
  3543. return WmipSetDosError(ERROR_INVALID_PARAMETER);
  3544. }
  3545. pContext = logfile->Context;
  3546. RTCxt = pContext->RealTimeCxt;
  3547. if (RTCxt == NULL) {
  3548. return WmipSetDosError(ERROR_INVALID_DATA);
  3549. }
  3550. if (pContext->EndOfFile != TRUE) {
  3551. pBuffer = pContext->BufferCache[0].Buffer;
  3552. pEvent = &pContext->Root->Event;
  3553. Status = ERROR_SUCCESS;
  3554. Size = 0;
  3555. if ((HeaderType = WmiGetTraceHeader(pBuffer, pContext->Root->BufferOffset, &Size)) != WMIHT_NONE) {
  3556. if (Size > 0) {
  3557. Status = WmipParseTraceEvent(pContext, pBuffer, pContext->Root->BufferOffset, HeaderType, pEvent, sizeof(EVENT_TRACE));
  3558. pContext->Root->BufferOffset += Size;
  3559. }
  3560. }
  3561. pContext->Root->EventSize = Size;
  3562. if ( ( Size > 0) && (Status == ERROR_SUCCESS) ) {
  3563. logfile->CurrentTime = pEvent->Header.TimeStamp.QuadPart;
  3564. return ERROR_SUCCESS;
  3565. }
  3566. else {
  3567. //
  3568. // When the current buffer is exhausted, make the
  3569. // BufferCallback
  3570. //
  3571. if (logfile->BufferCallback) {
  3572. ULONG bRetVal;
  3573. try {
  3574. bRetVal = (*logfile->BufferCallback) (logfile);
  3575. if (!bRetVal) {
  3576. return ERROR_CANCELLED;
  3577. }
  3578. } except (EXCEPTION_EXECUTE_HANDLER) {
  3579. pContext->EndOfFile = TRUE;
  3580. Status = GetExceptionCode();
  3581. #ifdef DBG
  3582. WmipDebugPrint(("TRACE: BufferCallback threw exception %X\n",
  3583. Status));
  3584. #endif
  3585. WmipSetDosError(WmipNtStatusToDosError(Status));
  3586. return ERROR_CANCELLED; // so that realtime also cleans up.
  3587. }
  3588. }
  3589. WmipFreeTraceBuffer(RTCxt, pBuffer);
  3590. }
  3591. }
  3592. pContext->EndOfFile = TRUE;
  3593. logfile->CurrentTime = 0;
  3594. BuffersRead = logfile->BuffersRead;
  3595. // Check to see if there are more buffers to consume.
  3596. if (BuffersRead < RTCxt->BuffersProduced) {
  3597. pContext->EndOfFile = FALSE;
  3598. index = (BuffersRead % MAXBUFFERS);
  3599. if ( RTCxt->RealTimeBufferPool[index] != NULL) {
  3600. PWMI_CLIENT_CONTEXT ClientContext;
  3601. PWNODE_HEADER Wnode;
  3602. pBuffer = (char*) (RTCxt->RealTimeBufferPool[index]);
  3603. pContext->BufferCache[0].Buffer = pBuffer;
  3604. RTCxt->RealTimeBufferPool[index] = NULL;
  3605. Wnode = (PWNODE_HEADER)pContext->BufferCache[0].Buffer;
  3606. pHeader = (PWMI_BUFFER_HEADER)pContext->BufferCache[0].Buffer;
  3607. Offset = sizeof(WMI_BUFFER_HEADER);
  3608. pEvent = &pContext->Root->Event;
  3609. if ((HeaderType = WmiGetTraceHeader(pBuffer, Offset, &Size)) != WMIHT_NONE) {
  3610. if (Size == 0)
  3611. return ERROR_INVALID_DATA;
  3612. Status = WmipParseTraceEvent(pContext, pBuffer, Offset, HeaderType, pEvent, sizeof(EVENT_TRACE));
  3613. if (Status != ERROR_SUCCESS) {
  3614. return Status;
  3615. }
  3616. }
  3617. Offset += Size;
  3618. pContext->Root->BufferOffset = Offset;
  3619. pContext->Root->EventSize = Size;
  3620. logfile->CurrentTime = pEvent->Header.TimeStamp.QuadPart;
  3621. // Since the RealTime Logger may have started after
  3622. // the consumer started, we have to get the buffersize
  3623. // like this.
  3624. logfile->BufferSize = Wnode->BufferSize;
  3625. logfile->Filled = (ULONG)pHeader->Offset;
  3626. logfile->EventsLost = pHeader->EventsLost;
  3627. logfile->BuffersRead++;
  3628. }
  3629. }
  3630. return ERROR_SUCCESS;
  3631. }
  3632. ULONG
  3633. WmipCheckForRealTimeLoggers(
  3634. PEVENT_TRACE_LOGFILEW *Logfiles,
  3635. ULONG LogfileCount,
  3636. ULONG Unicode)
  3637. {
  3638. ULONG Status;
  3639. TRACEHANDLE LoggerHandle = 0;
  3640. ULONG i;
  3641. for (i=0; i < LogfileCount; i++) {
  3642. //
  3643. // Check to see if this is a RealTime Datafeed
  3644. //
  3645. if (Logfiles[i]->LogFileMode & EVENT_TRACE_REAL_TIME_MODE) {
  3646. //
  3647. // Using the LoggerName, Query the Logger to determine
  3648. // whether this is a Kernel or Usermode realtime logger.
  3649. //
  3650. RtlZeroMemory(&Properties, sizeof(Properties) );
  3651. Properties.TraceProp.Wnode.BufferSize = sizeof(Properties);
  3652. if (Unicode)
  3653. Status = ControlTraceW(LoggerHandle,
  3654. (LPWSTR)Logfiles[i]->LoggerName,
  3655. &Properties.TraceProp,
  3656. EVENT_TRACE_CONTROL_QUERY);
  3657. else
  3658. Status = ControlTraceA(LoggerHandle,
  3659. (LPSTR)Logfiles[i]->LoggerName,
  3660. (PEVENT_TRACE_PROPERTIES)&Properties,
  3661. EVENT_TRACE_CONTROL_QUERY);
  3662. //
  3663. // If the Logger is still around and the Real Time bit
  3664. // is still set continue processing. Otherwise quit.
  3665. //
  3666. if ((Status == ERROR_SUCCESS) && (Properties.TraceProp.LogFileMode & EVENT_TRACE_REAL_TIME_MODE) ){
  3667. return TRUE;
  3668. }
  3669. }
  3670. }
  3671. #ifdef DBG
  3672. //
  3673. // We are expecting to see ERROR_WMI_INSTANCE_NOT_FOUND when the logger has gone away.
  3674. // Any other error is abnormal.
  3675. //
  3676. if ( Status != ERROR_WMI_INSTANCE_NOT_FOUND ) {
  3677. WmipDebugPrint(("WET: WmipCheckForRealTimeLoggers abnormal failure. Status %X\n", Status));
  3678. }
  3679. #endif
  3680. return FALSE;
  3681. }
  3682. void
  3683. WmipFreeRealTimeContext(
  3684. PTRACELOG_REALTIME_CONTEXT RTCxt
  3685. )
  3686. {
  3687. ULONG Status;
  3688. PTRACERT_BUFFER_LIST_ENTRY ListEntry;
  3689. PLIST_ENTRY Head, Next;
  3690. if (RTCxt != NULL) {
  3691. Status = WmiNotificationRegistration(
  3692. (const LPGUID) &RTCxt->InstanceGuid,
  3693. FALSE,
  3694. WmipRealTimeCallback,
  3695. 0,
  3696. NOTIFICATION_CALLBACK_DIRECT
  3697. );
  3698. }
  3699. if (RTCxt->MoreDataEvent != NULL) {
  3700. NtClose(RTCxt->MoreDataEvent);
  3701. }
  3702. if (RTCxt->WmipTraceBufferSpace != NULL) {
  3703. WmipMemFree(RTCxt->WmipTraceBufferSpace->Space);
  3704. Head = &RTCxt->WmipTraceBufferSpace->FreeListHead;
  3705. Next = Head->Flink;
  3706. while (Head != Next) {
  3707. ListEntry = CONTAINING_RECORD(Next, TRACERT_BUFFER_LIST_ENTRY, Entry);
  3708. Next = Next->Flink;
  3709. RemoveEntryList(&ListEntry->Entry);
  3710. WmipFree(ListEntry);
  3711. }
  3712. WmipFree(RTCxt->WmipTraceBufferSpace);
  3713. RTCxt->WmipTraceBufferSpace = NULL;
  3714. }
  3715. WmipFree(RTCxt);
  3716. }
  3717. ULONG
  3718. WmipProcessRealTimeTraces(
  3719. PTRACEHANDLE HandleArray,
  3720. PEVENT_TRACE_LOGFILEW *Logfiles,
  3721. ULONG LogfileCount,
  3722. LONGLONG StartTime,
  3723. LONGLONG EndTime,
  3724. ULONG Unicode
  3725. )
  3726. /*++
  3727. Routine Description:
  3728. Main entry point to process RealTime trace data streams.
  3729. Arguments:
  3730. Logfiles Array of logfile structures with LoggerNames of the RT stream
  3731. LogfileCount Number of RealTime trace streams to process
  3732. StartTime StartTime for windowing data
  3733. EndTime EndTime for windowing data
  3734. Returned Value:
  3735. ERROR_SUCCESS Successfully processed data from realtime trace stream
  3736. --*/
  3737. {
  3738. ULONG Status;
  3739. BOOL Done = FALSE;
  3740. ULONG i, j;
  3741. PTRACELOG_CONTEXT pContext;
  3742. HANDLE EventArray[MAXLOGGERS];
  3743. NTSTATUS NtStatus;
  3744. LARGE_INTEGER timeout = {(ULONG)(-1 * 10 * 1000 * 1000 * 10), -1}; // Wait for 10 seconds
  3745. //
  3746. // Register for RealTime Callbacks
  3747. //
  3748. Status = WmipSetupRealTimeContext( HandleArray, Logfiles, LogfileCount);
  3749. if (Status != ERROR_SUCCESS) {
  3750. goto DoCleanup;
  3751. }
  3752. //
  3753. // Build the Handle Array
  3754. //
  3755. for (j=0; j < LogfileCount; j++) {
  3756. pContext = (PTRACELOG_CONTEXT)Logfiles[j]->Context;
  3757. EventArray[j] = pContext->RealTimeCxt->MoreDataEvent;
  3758. }
  3759. //
  3760. // Event Processing Loop
  3761. //
  3762. while (!Done) {
  3763. LONGLONG nextTimeStamp;
  3764. BOOL EventInRange;
  3765. PEVENT_TRACE_LOGFILEW logfile;
  3766. ULONG j;
  3767. PTRACELOG_CONTEXT pContext;
  3768. //
  3769. // Check to see if end of file has been reached on all the
  3770. // files.
  3771. //
  3772. logfile = NULL;
  3773. nextTimeStamp = 0;
  3774. for (j=0; j < LogfileCount; j++) {
  3775. pContext = (PTRACELOG_CONTEXT)Logfiles[j]->Context;
  3776. if ((pContext->EndOfFile) &&
  3777. (Logfiles[j]->LogFileMode & EVENT_TRACE_REAL_TIME_MODE)) {
  3778. WmipLookforRealTimeBuffers(Logfiles[j]);
  3779. }
  3780. if (pContext->EndOfFile)
  3781. continue;
  3782. if (nextTimeStamp == 0) {
  3783. nextTimeStamp = Logfiles[j]->CurrentTime;
  3784. logfile = Logfiles[j];
  3785. }
  3786. else if (nextTimeStamp > Logfiles[j]->CurrentTime) {
  3787. nextTimeStamp = Logfiles[j]->CurrentTime;
  3788. logfile = Logfiles[j];
  3789. }
  3790. }
  3791. if (logfile == NULL) {
  3792. //
  3793. // If no logfile with events found, wait on the realtime event.
  3794. // If no realtime datafeed, then we are done.
  3795. //
  3796. NtStatus = NtWaitForMultipleObjects(LogfileCount, &EventArray[0], WaitAny, FALSE, &timeout);
  3797. if (NtStatus == STATUS_TIMEOUT) {
  3798. //
  3799. // If we timed out, then check to see if the loggers have gone away.
  3800. //
  3801. if ( !WmipCheckForRealTimeLoggers(Logfiles, LogfileCount, Unicode) ) {
  3802. break;
  3803. }
  3804. }
  3805. continue;
  3806. break;
  3807. }
  3808. //
  3809. // if the Next event timestamp is not within the window of
  3810. // analysis, we do not fire the event callbacks.
  3811. //
  3812. EventInRange = TRUE;
  3813. if ((StartTime != 0) && (StartTime > nextTimeStamp))
  3814. EventInRange = FALSE;
  3815. if ((EndTime != 0) && (EndTime < nextTimeStamp))
  3816. EventInRange = FALSE;
  3817. //
  3818. // Make the Event Callbacks
  3819. //
  3820. if (EventInRange) {
  3821. PEVENT_TRACE pEvent = &pContext->Root->Event;
  3822. Status = WmipDoEventCallbacks( logfile, pEvent);
  3823. if (Status != ERROR_SUCCESS) {
  3824. return Status;
  3825. }
  3826. }
  3827. //
  3828. // Now advance to next event.
  3829. //
  3830. Status = WmipLookforRealTimeBuffers(logfile);
  3831. Done = (Status == ERROR_CANCELLED);
  3832. }
  3833. DoCleanup:
  3834. for (i=0; i < LogfileCount; i++) {
  3835. pContext = (PTRACELOG_CONTEXT)Logfiles[i]->Context;
  3836. if (pContext != NULL) {
  3837. WmipCleanupTraceLog(pContext);
  3838. }
  3839. }
  3840. return Status;
  3841. }
  3842. ULONG
  3843. WMIAPI
  3844. WmiOpenTraceWithCursor(
  3845. IN PWMI_MERGE_ETL_CURSOR LogCursor
  3846. )
  3847. /*++
  3848. Routine Description:
  3849. Main entry point to process Merged ETL file.
  3850. Arguments:
  3851. LogCursor pointer to WMI_MERGE_ETL_CURSOR
  3852. Returned Value:
  3853. Status
  3854. --*/
  3855. {
  3856. ULONG DosStatus = ERROR_INVALID_PARAMETER;
  3857. NTSTATUS Status;
  3858. PTRACELOG_CONTEXT HandleEntry = NULL;
  3859. TRACEHANDLE TraceHandle = (TRACEHANDLE)INVALID_HANDLE_VALUE;
  3860. PEVENT_TRACE_LOGFILEW Logfile;
  3861. PTRACELOG_CONTEXT pContext;
  3862. ULONG BufferSize;
  3863. PWMI_BUFFER_HEADER BufferHeader;
  3864. ULONG CpuNum;
  3865. BOOLEAN CpuBufferFound;
  3866. WmipInitProcessHeap();
  3867. if (LogCursor != NULL) {
  3868. LogCursor->Base = NULL;
  3869. LogCursor->TraceMappingHandle = NULL;
  3870. LogCursor->CursorVersion = WMI_MERGE_ETL_CURSOR_VERSION;
  3871. Logfile = &LogCursor->Logfile;
  3872. HandleEntry = WmipAllocateTraceHandle();
  3873. if (HandleEntry == NULL) {
  3874. DosStatus = ERROR_OUTOFMEMORY;
  3875. } else {
  3876. TraceHandle = HandleEntry->TraceHandle;
  3877. try {
  3878. DosStatus = WmipCopyLogfileInfo( HandleEntry,
  3879. Logfile,
  3880. TRUE
  3881. );
  3882. if (DosStatus == ERROR_SUCCESS) {
  3883. DosStatus = WmipCreateGuidMapping();
  3884. if (DosStatus == ERROR_SUCCESS) {
  3885. DosStatus = WmipProcessLogHeader( &HandleEntry->TraceHandle,
  3886. &Logfile,
  3887. 1,
  3888. TRUE,
  3889. FALSE
  3890. );
  3891. }
  3892. }
  3893. } except (EXCEPTION_EXECUTE_HANDLER) {
  3894. DosStatus = WmipNtStatusToDosError( GetExceptionCode() );
  3895. }
  3896. }
  3897. }
  3898. if (DosStatus == ERROR_SUCCESS) {
  3899. //
  3900. // Now Make sure the bit was set, indicating a MERGED ETL
  3901. //
  3902. if ((LogCursor->Logfile.LogFileMode & EVENT_TRACE_RELOG_MODE) == 0) {
  3903. //
  3904. // It is not Merged ETL.
  3905. //
  3906. DosStatus = ERROR_BAD_FORMAT;
  3907. } else {
  3908. //
  3909. // Now find out the number of CPU's, Current event, etc.
  3910. //
  3911. pContext = LogCursor->Logfile.Context;
  3912. //
  3913. // Now Create a file Mapping
  3914. //
  3915. LogCursor->TraceMappingHandle =
  3916. CreateFileMapping(pContext->Handle,
  3917. 0,
  3918. PAGE_READONLY,
  3919. 0,
  3920. 0,
  3921. NULL
  3922. );
  3923. if (LogCursor->TraceMappingHandle == NULL) {
  3924. DosStatus = GetLastError();
  3925. return DosStatus;
  3926. }
  3927. //
  3928. // MapView of the file
  3929. //
  3930. LogCursor->Base = MapViewOfFile(LogCursor->TraceMappingHandle,
  3931. FILE_MAP_READ,
  3932. 0,
  3933. 0,
  3934. 0);
  3935. if (LogCursor->Base == NULL) {
  3936. DosStatus = GetLastError();
  3937. return DosStatus;
  3938. }
  3939. //
  3940. // Now find the first event of each CPU
  3941. //
  3942. pContext = LogCursor->Logfile.Context;
  3943. BufferSize = pContext->BufferSize;
  3944. LogCursor->CurrentCpu = 0;
  3945. for (CpuNum = 0; CpuNum < LogCursor->Logfile.LogfileHeader.NumberOfProcessors; CpuNum++) {
  3946. CpuBufferFound = FALSE;
  3947. while (CpuBufferFound == FALSE) {
  3948. BufferHeader = (PWMI_BUFFER_HEADER)
  3949. ((UCHAR*) LogCursor->Base +
  3950. LogCursor->BufferCursor[CpuNum].CurrentBufferOffset.QuadPart);
  3951. if (BufferHeader->ClientContext.ProcessorNumber == CpuNum) {
  3952. CpuBufferFound = TRUE;
  3953. LogCursor->BufferCursor[CpuNum].BufferHeader = BufferHeader;
  3954. } else {
  3955. LogCursor->BufferCursor[CpuNum].CurrentBufferOffset.QuadPart += BufferSize;
  3956. if ((LogCursor->BufferCursor[CpuNum].CurrentBufferOffset.QuadPart/BufferSize) >=
  3957. LogCursor->Logfile.LogfileHeader.BuffersWritten) {
  3958. //
  3959. // Scanned the whole file;
  3960. //
  3961. LogCursor->BufferCursor[CpuNum].NoMoreEvents = TRUE;
  3962. break;
  3963. }
  3964. }
  3965. }
  3966. if (CpuBufferFound) {
  3967. //
  3968. // Found the buffer, set the offset
  3969. //
  3970. ULONG Size;
  3971. WMI_HEADER_TYPE HeaderType = WMIHT_NONE;
  3972. PVOID pBuffer;
  3973. LogCursor->BufferCursor[CpuNum].BufferHeader = BufferHeader;
  3974. LogCursor->BufferCursor[CpuNum].CurrentEventOffset = sizeof(WMI_BUFFER_HEADER);
  3975. //
  3976. // Initialize the first event in each CPU Stream.
  3977. //
  3978. pBuffer = LogCursor->BufferCursor[CpuNum].BufferHeader;
  3979. HeaderType = WmiGetTraceHeader(pBuffer,
  3980. LogCursor->BufferCursor[CpuNum].CurrentEventOffset,
  3981. &Size);
  3982. if (HeaderType != WMIHT_NONE) {
  3983. WmipParseTraceEvent(pContext,
  3984. pBuffer,
  3985. LogCursor->BufferCursor[CpuNum].CurrentEventOffset,
  3986. HeaderType,
  3987. &LogCursor->BufferCursor[CpuNum].CurrentEvent,
  3988. sizeof(EVENT_TRACE));
  3989. LogCursor->BufferCursor[CpuNum].CurrentEventOffset += Size;
  3990. LogCursor->CurrentCpu = CpuNum;
  3991. } else {
  3992. //
  3993. // There is no event in this buffer.
  3994. //
  3995. DosStatus = ERROR_FILE_CORRUPT;
  3996. return DosStatus;
  3997. }
  3998. }
  3999. }
  4000. for (CpuNum = 0; CpuNum < LogCursor->Logfile.LogfileHeader.NumberOfProcessors; CpuNum++) {
  4001. //
  4002. // Find the first event for whole trace.
  4003. //
  4004. if (LogCursor->BufferCursor[CpuNum].NoMoreEvents == FALSE) {
  4005. if (LogCursor->BufferCursor[LogCursor->CurrentCpu].CurrentEvent.Header.TimeStamp.QuadPart >
  4006. LogCursor->BufferCursor[CpuNum].CurrentEvent.Header.TimeStamp.QuadPart) {
  4007. LogCursor->CurrentCpu = CpuNum;
  4008. }
  4009. }
  4010. }
  4011. }
  4012. } else if ( HandleEntry != NULL) {
  4013. WmipFreeTraceHandle(TraceHandle);
  4014. TraceHandle = (TRACEHANDLE)INVALID_HANDLE_VALUE;
  4015. }
  4016. WmipSetDosError(DosStatus);
  4017. return DosStatus;
  4018. }
  4019. ULONG
  4020. WMIAPI
  4021. WmiCloseTraceWithCursor(
  4022. IN PWMI_MERGE_ETL_CURSOR LogCursor
  4023. )
  4024. {
  4025. ULONG Status = ERROR_INVALID_PARAMETER;
  4026. if (LogCursor != NULL) {
  4027. if (LogCursor->Base != NULL) {
  4028. if (UnmapViewOfFile(LogCursor->Base) == FALSE) {
  4029. Status = GetLastError();
  4030. return Status;
  4031. } else {
  4032. Status = ERROR_SUCCESS;
  4033. }
  4034. } else {
  4035. Status = ERROR_INVALID_PARAMETER;
  4036. }
  4037. if (Status != ERROR_SUCCESS) {
  4038. return Status;
  4039. }
  4040. if (LogCursor->TraceMappingHandle != NULL) {
  4041. if (CloseHandle(LogCursor->TraceMappingHandle) == FALSE) {
  4042. Status = GetLastError();
  4043. return Status;
  4044. } else {
  4045. Status = ERROR_SUCCESS;
  4046. }
  4047. } else {
  4048. Status = ERROR_INVALID_PARAMETER;
  4049. }
  4050. }
  4051. return Status;
  4052. }
  4053. VOID
  4054. WMIAPI
  4055. WmiConvertTimestamp(
  4056. OUT PLARGE_INTEGER DestTime,
  4057. IN PLARGE_INTEGER SrcTime,
  4058. IN PWMI_MERGE_ETL_CURSOR LogCursor
  4059. )
  4060. {
  4061. WmipCalculateCurrentTime(DestTime, SrcTime, LogCursor->Logfile.Context);
  4062. }
  4063. ULONG
  4064. WMIAPI
  4065. WmiGetNextEvent(
  4066. IN PWMI_MERGE_ETL_CURSOR LogCursor
  4067. )
  4068. {
  4069. ULONG CurrentCpu = LogCursor->CurrentCpu;
  4070. ULONG Size;
  4071. WMI_HEADER_TYPE HeaderType = WMIHT_NONE;
  4072. PVOID pBuffer;
  4073. PWMI_BUFFER_HEADER BufferHeader;
  4074. ULONG BufferSize;
  4075. PTRACELOG_CONTEXT pContext;
  4076. ULONG CpuNum;
  4077. NTSTATUS Status;
  4078. ULONG i;
  4079. BOOLEAN CpuBufferFound = FALSE;
  4080. BOOLEAN MoreEvents = FALSE;
  4081. if (LogCursor == NULL) {
  4082. return MoreEvents;
  4083. }
  4084. //
  4085. // Advance to the next event of this current CPU
  4086. //
  4087. retry:
  4088. pBuffer = LogCursor->BufferCursor[CurrentCpu].BufferHeader;
  4089. HeaderType = WmiGetTraceHeader(pBuffer,
  4090. LogCursor->BufferCursor[CurrentCpu].CurrentEventOffset,
  4091. &Size);
  4092. pContext = LogCursor->Logfile.Context;
  4093. if (HeaderType == WMIHT_NONE) {
  4094. //
  4095. // End of current buffer, advance to the next buffer for this CPU
  4096. //
  4097. BufferSize = pContext->BufferSize;
  4098. LogCursor->BufferCursor[CurrentCpu].CurrentBufferOffset.QuadPart
  4099. = LogCursor->BufferCursor[CurrentCpu].CurrentBufferOffset.QuadPart
  4100. + BufferSize;
  4101. if ((LogCursor->BufferCursor[CurrentCpu].CurrentBufferOffset.QuadPart/BufferSize) >=
  4102. LogCursor->Logfile.LogfileHeader.BuffersWritten) {
  4103. //
  4104. // Scanned the whole file;
  4105. //
  4106. LogCursor->BufferCursor[CurrentCpu].NoMoreEvents = TRUE;
  4107. } else {
  4108. while (CpuBufferFound == FALSE) {
  4109. BufferHeader = (PWMI_BUFFER_HEADER)
  4110. ((UCHAR*) LogCursor->Base +
  4111. LogCursor->BufferCursor[CurrentCpu].CurrentBufferOffset.QuadPart);
  4112. if (BufferHeader->ClientContext.ProcessorNumber == CurrentCpu) {
  4113. CpuBufferFound = TRUE;
  4114. } else {
  4115. LogCursor->BufferCursor[CurrentCpu].CurrentBufferOffset.QuadPart += BufferSize;
  4116. if ((LogCursor->BufferCursor[CurrentCpu].CurrentBufferOffset.QuadPart/BufferSize) >=
  4117. LogCursor->Logfile.LogfileHeader.BuffersWritten) {
  4118. //
  4119. // Scanned the whole file;
  4120. //
  4121. LogCursor->BufferCursor[CurrentCpu].NoMoreEvents = TRUE;
  4122. break;
  4123. }
  4124. }
  4125. }
  4126. }
  4127. if (CpuBufferFound) {
  4128. //
  4129. // Found the buffer, set the offset
  4130. //
  4131. LogCursor->BufferCursor[CurrentCpu].BufferHeader = BufferHeader;
  4132. LogCursor->BufferCursor[CurrentCpu].CurrentEventOffset = sizeof(WMI_BUFFER_HEADER);
  4133. goto retry;
  4134. } else {
  4135. //
  4136. // No more buffer in this CPU stream.
  4137. //
  4138. LogCursor->BufferCursor[CurrentCpu].NoMoreEvents = TRUE;
  4139. }
  4140. } else {
  4141. WmipParseTraceEvent(pContext,
  4142. pBuffer,
  4143. LogCursor->BufferCursor[CurrentCpu].CurrentEventOffset,
  4144. HeaderType,
  4145. &LogCursor->BufferCursor[CurrentCpu].CurrentEvent,
  4146. sizeof(EVENT_TRACE));
  4147. LogCursor->BufferCursor[CurrentCpu].CurrentEventOffset += Size;
  4148. MoreEvents = TRUE;
  4149. }
  4150. //
  4151. // No more events in current CPU.
  4152. //
  4153. if (MoreEvents == FALSE) {
  4154. for (CurrentCpu=0; CurrentCpu<LogCursor->Logfile.LogfileHeader.NumberOfProcessors; CurrentCpu++) {
  4155. if (LogCursor->BufferCursor[CurrentCpu].NoMoreEvents == FALSE) {
  4156. LogCursor->CurrentCpu = CurrentCpu;
  4157. MoreEvents = TRUE;
  4158. break;
  4159. }
  4160. }
  4161. }
  4162. //
  4163. // Now find the CPU that has the next event
  4164. //
  4165. if (MoreEvents == TRUE) {
  4166. for (i=0; i<LogCursor->Logfile.LogfileHeader.NumberOfProcessors; i++) {
  4167. if (LogCursor->BufferCursor[i].NoMoreEvents == FALSE) {
  4168. if (LogCursor->BufferCursor[LogCursor->CurrentCpu].CurrentEvent.Header.TimeStamp.QuadPart >
  4169. LogCursor->BufferCursor[i].CurrentEvent.Header.TimeStamp.QuadPart) {
  4170. LogCursor->CurrentCpu = i;
  4171. }
  4172. }
  4173. }
  4174. }
  4175. //
  4176. // Finish finding the next event.
  4177. //
  4178. return MoreEvents;
  4179. }
  4180. #endif