Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3524 lines
109 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 "tracep.h"
  16. PLIST_ENTRY EventCallbackListHead = NULL;
  17. ETW_QUERY_PROPERTIES QueryProperties;
  18. PTRACE_GUID_MAP EventMapList = NULL;
  19. PLIST_ENTRY TraceHandleListHeadPtr = NULL;
  20. VOID
  21. EtwpInsertBuffer (
  22. PTRACE_BUFFER_LIST_ENTRY *Root,
  23. PTRACE_BUFFER_LIST_ENTRY NewEntry
  24. )
  25. /*++
  26. Routine Description:
  27. This routine inserts a buffer in a sorted list. The insertion
  28. is done based on the timestamp of the BufferHeader. If two buffers
  29. have the same timestamp, then the BufferIndex is used to resolve the tie.
  30. Arguments:
  31. Root - Pointer to the root of the LIST
  32. NewEntry - Entry being inserted
  33. Returned Value:
  34. None
  35. --*/
  36. {
  37. PTRACE_BUFFER_LIST_ENTRY Current, Prev;
  38. //
  39. // If List is empty, make the new entry the Root and return.
  40. //
  41. if (NewEntry == NULL) {
  42. return;
  43. }
  44. if (*Root == NULL) {
  45. *Root = NewEntry;
  46. NewEntry->Next = NULL;
  47. return;
  48. }
  49. //
  50. // Traverse the list and insert the NewEntry in order
  51. //
  52. Prev = NULL;
  53. Current = *Root;
  54. while (Current != NULL) {
  55. if ((ULONGLONG)NewEntry->Event.Header.TimeStamp.QuadPart <
  56. (ULONGLONG)Current->Event.Header.TimeStamp.QuadPart) {
  57. if (Prev != NULL) {
  58. Prev->Next = NewEntry;
  59. }
  60. else {
  61. *Root = NewEntry;
  62. }
  63. NewEntry->Next = Current;
  64. return;
  65. }
  66. else if ((ULONGLONG)NewEntry->Event.Header.TimeStamp.QuadPart ==
  67. (ULONGLONG)Current->Event.Header.TimeStamp.QuadPart) {
  68. if (NewEntry->FileOffset < Current->FileOffset) {
  69. if (Prev != NULL) {
  70. Prev->Next = NewEntry;
  71. }
  72. else {
  73. *Root = NewEntry;
  74. }
  75. NewEntry->Next = Current;
  76. return;
  77. }
  78. }
  79. Prev = Current;
  80. Current = Current->Next;
  81. }
  82. if (Prev != NULL) {
  83. Prev->Next = NewEntry;
  84. NewEntry->Next = NULL;
  85. }
  86. #if DBG
  87. else {
  88. EtwpAssert(Prev != NULL);
  89. }
  90. #endif
  91. return;
  92. }
  93. PTRACE_BUFFER_LIST_ENTRY
  94. EtwpRemoveBuffer(
  95. PTRACE_BUFFER_LIST_ENTRY *Root
  96. )
  97. {
  98. PTRACE_BUFFER_LIST_ENTRY OldEntry = *Root;
  99. if (OldEntry == NULL)
  100. return NULL;
  101. *Root = OldEntry->Next;
  102. OldEntry->Next = NULL;
  103. return OldEntry;
  104. }
  105. PVOID
  106. EtwpGetCurrentBuffer(
  107. PTRACELOG_CONTEXT pContext,
  108. PTRACE_BUFFER_LIST_ENTRY Current
  109. )
  110. {
  111. NTSTATUS Status;
  112. LONG FileOffset = (ULONG)Current->FileOffset;
  113. ULONG nBytesRead;
  114. LONG TableIndex;
  115. HANDLE hFile = pContext->Handle;
  116. ULONG BufferSize = pContext->BufferSize;
  117. PVOID pBuffer;
  118. ULONGLONG Offset;
  119. DWORD BytesTransffered;
  120. //
  121. // Look for the buffer in cache.
  122. //
  123. TableIndex = FileOffset % MAX_TRACE_BUFFER_CACHE_SIZE;
  124. if (pContext->BufferCache[TableIndex].Index == FileOffset) {
  125. //
  126. // Check whether the buffer we want is still being read.
  127. // If so, we need to wait for it to finish.
  128. //
  129. if (pContext->BufferBeingRead == FileOffset) {
  130. if (GetOverlappedResult(hFile, &pContext->AsynchRead, &BytesTransffered, TRUE)) {
  131. pContext->BufferBeingRead = -1;
  132. }
  133. else { // getting the result failed
  134. return NULL;
  135. }
  136. }
  137. return pContext->BufferCache[TableIndex].Buffer;
  138. }
  139. //
  140. // Do a synch read for the buffer we need. We still need to make sure the
  141. // previous read has completed.
  142. //
  143. pBuffer = pContext->BufferCache[TableIndex].Buffer;
  144. Offset = FileOffset * BufferSize;
  145. if (pContext->BufferBeingRead != -1) {
  146. if (!GetOverlappedResult(hFile, &pContext->AsynchRead, &BytesTransffered, TRUE) &&
  147. GetLastError() != ERROR_HANDLE_EOF) {
  148. EtwpDebugPrint(("GetOverlappedResult failed with Status %d in GetCurrentBuffer\n", GetLastError()));
  149. // cannot determine the status of the previous read
  150. return NULL;
  151. }
  152. }
  153. // Not necessary, but PREFIX likes it.
  154. nBytesRead = 0;
  155. pContext->AsynchRead.Offset = (DWORD)(Offset & 0xFFFFFFFF);
  156. pContext->AsynchRead.OffsetHigh = (DWORD)(Offset >> 32);
  157. Status = EtwpSynchReadFile(hFile,
  158. (LPVOID)pBuffer,
  159. BufferSize,
  160. &nBytesRead,
  161. &pContext->AsynchRead);
  162. pContext->BufferBeingRead = -1;
  163. if (nBytesRead == 0) {
  164. return NULL;
  165. }
  166. //
  167. // Update the cache entry with the one just read in
  168. //
  169. pContext->BufferCache[TableIndex].Index = FileOffset;
  170. //
  171. // We need to account for event alignments when backtracking to get the MofPtr.
  172. // (BufferOffset - EventSize) backtracks to the start of the current event.
  173. // Add EventHeaderSize and Subtract the MofLength gives the MofPtr.
  174. //
  175. if (pContext->ConversionFlags & EVENT_TRACE_GET_RAWEVENT) {
  176. Current->Event.MofData = ((PUCHAR)pBuffer
  177. + Current->BufferOffset
  178. - Current->EventSize);
  179. if (pContext->UsePerfClock == EVENT_TRACE_CLOCK_PERFCOUNTER) {
  180. //
  181. // Need to override the timestamp with SystemTime
  182. //
  183. switch(Current->TraceType) {
  184. case TRACE_HEADER_TYPE_PERFINFO32:
  185. case TRACE_HEADER_TYPE_PERFINFO64:
  186. {
  187. PPERFINFO_TRACE_HEADER pPerf;
  188. pPerf = (PPERFINFO_TRACE_HEADER)Current->Event.MofData;
  189. pPerf->SystemTime = Current->Event.Header.TimeStamp;
  190. break;
  191. }
  192. case TRACE_HEADER_TYPE_SYSTEM32:
  193. {
  194. PSYSTEM_TRACE_HEADER pSystemHeader32;
  195. pSystemHeader32 = (PSYSTEM_TRACE_HEADER)
  196. Current->Event.MofData;
  197. pSystemHeader32->SystemTime =
  198. Current->Event.Header.TimeStamp;
  199. break;
  200. }
  201. case TRACE_HEADER_TYPE_SYSTEM64:
  202. {
  203. PSYSTEM_TRACE_HEADER pSystemHeader64;
  204. pSystemHeader64 = (PSYSTEM_TRACE_HEADER)
  205. Current->Event.MofData;
  206. pSystemHeader64->SystemTime =
  207. Current->Event.Header.TimeStamp;
  208. break;
  209. }
  210. case TRACE_HEADER_TYPE_FULL_HEADER:
  211. {
  212. PEVENT_TRACE_HEADER pWnodeHeader = (PEVENT_TRACE_HEADER) Current->Event.MofData;
  213. pWnodeHeader->TimeStamp = Current->Event.Header.TimeStamp;
  214. break;
  215. }
  216. case TRACE_HEADER_TYPE_INSTANCE:
  217. {
  218. if (((pContext->Logfile.LogfileHeader.VersionDetail.SubVersion >= 1) &&
  219. (pContext->Logfile.LogfileHeader.VersionDetail.SubMinorVersion >= 1)) ||
  220. pContext->Logfile.LogFileMode & EVENT_TRACE_REAL_TIME_MODE) {
  221. // Use new header for event instances.
  222. PEVENT_INSTANCE_GUID_HEADER pInstanceHeader = (PEVENT_INSTANCE_GUID_HEADER) Current->Event.MofData;
  223. pInstanceHeader->TimeStamp = Current->Event.Header.TimeStamp;
  224. }
  225. else {
  226. PEVENT_INSTANCE_HEADER pInstanceHeader = (PEVENT_INSTANCE_HEADER) Current->Event.MofData;
  227. pInstanceHeader->TimeStamp = Current->Event.Header.TimeStamp;
  228. }
  229. break;
  230. }
  231. case TRACE_HEADER_TYPE_TIMED:
  232. {
  233. PTIMED_TRACE_HEADER pTimedHeader = (PTIMED_TRACE_HEADER) Current->Event.MofData;
  234. pTimedHeader->TimeStamp = Current->Event.Header.TimeStamp;
  235. break;
  236. }
  237. case TRACE_HEADER_TYPE_WNODE_HEADER:
  238. break;
  239. case TRACE_HEADER_TYPE_MESSAGE:
  240. { PEVENT_TRACE_HEADER pWnodeHeader = (PEVENT_TRACE_HEADER) Current->Event.MofData ;
  241. pWnodeHeader->TimeStamp = Current->Event.Header.TimeStamp;
  242. break;
  243. }
  244. }
  245. }
  246. }
  247. else {
  248. //
  249. // When The FileOffset is 0 (First Buffer) and the EventType is
  250. // LOGFILE_HEADER
  251. //
  252. if ( (FileOffset == 0) &&
  253. ((Current->BufferOffset - Current->EventSize) == sizeof(WMI_BUFFER_HEADER)) )
  254. {
  255. PTRACE_LOGFILE_HEADER pLogHeader = (PTRACE_LOGFILE_HEADER)((PUCHAR)pBuffer
  256. + Current->BufferOffset
  257. - Current->EventSize
  258. + sizeof(SYSTEM_TRACE_HEADER));
  259. pLogHeader->LoggerName = (LPWSTR)((PUCHAR)pLogHeader + sizeof(TRACE_LOGFILE_HEADER));
  260. pLogHeader->LogFileName = (LPWSTR)((PUCHAR)pLogHeader + sizeof(TRACE_LOGFILE_HEADER)
  261. + (wcslen(pLogHeader->LoggerName) + 1) * sizeof(WCHAR));
  262. Current->Event.MofData = (PUCHAR)pLogHeader;
  263. }
  264. else
  265. {
  266. Current->Event.MofData = ((PUCHAR)pBuffer
  267. + Current->BufferOffset
  268. - Current->EventSize
  269. + Current->Event.Header.Size
  270. - Current->Event.MofLength );
  271. }
  272. }
  273. return pBuffer;
  274. }
  275. PTRACELOG_CONTEXT
  276. EtwpAllocateTraceHandle()
  277. {
  278. PLIST_ENTRY Next, Head;
  279. PTRACELOG_CONTEXT NewHandleEntry, pEntry;
  280. EtwpEnterPMCritSection();
  281. if (TraceHandleListHeadPtr == NULL) {
  282. TraceHandleListHeadPtr = EtwpAlloc(sizeof(LIST_ENTRY));
  283. if (TraceHandleListHeadPtr == NULL) {
  284. EtwpLeavePMCritSection();
  285. return NULL;
  286. }
  287. InitializeListHead(TraceHandleListHeadPtr);
  288. }
  289. NewHandleEntry = EtwpAlloc(sizeof(TRACELOG_CONTEXT));
  290. if (NewHandleEntry == NULL) {
  291. EtwpLeavePMCritSection();
  292. return NULL;
  293. }
  294. RtlZeroMemory(NewHandleEntry, sizeof(TRACELOG_CONTEXT));
  295. // AsynchRead initialization
  296. NewHandleEntry->BufferBeingRead = -1;
  297. NewHandleEntry->AsynchRead.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
  298. if (NewHandleEntry->AsynchRead.hEvent == NULL) {
  299. EtwpFree(NewHandleEntry);
  300. EtwpLeavePMCritSection();
  301. return NULL;
  302. }
  303. InitializeListHead(&NewHandleEntry->StreamListHead);
  304. InitializeListHead(&NewHandleEntry->GuidMapListHead);
  305. Head = TraceHandleListHeadPtr;
  306. Next = Head->Flink;
  307. if (Next == Head) {
  308. NewHandleEntry->TraceHandle = 1;
  309. InsertTailList(Head, &NewHandleEntry->Entry);
  310. EtwpLeavePMCritSection();
  311. return NewHandleEntry;
  312. }
  313. while (Next != Head) {
  314. pEntry = CONTAINING_RECORD( Next, TRACELOG_CONTEXT, Entry );
  315. Next = Next->Flink;
  316. NewHandleEntry->TraceHandle++;
  317. if (NewHandleEntry->TraceHandle < pEntry->TraceHandle) {
  318. InsertTailList(&pEntry->Entry, &NewHandleEntry->Entry);
  319. EtwpLeavePMCritSection();
  320. return NewHandleEntry;
  321. }
  322. }
  323. //
  324. // TODO: Need to optimize this case out first before searching...
  325. //
  326. NewHandleEntry->TraceHandle++;
  327. InsertTailList(Head, &NewHandleEntry->Entry);
  328. EtwpLeavePMCritSection();
  329. return NewHandleEntry;
  330. }
  331. PTRACELOG_CONTEXT
  332. EtwpLookupTraceHandle(
  333. TRACEHANDLE TraceHandle
  334. )
  335. {
  336. PLIST_ENTRY Head, Next;
  337. PTRACELOG_CONTEXT pEntry;
  338. EtwpEnterPMCritSection();
  339. Head = TraceHandleListHeadPtr;
  340. if (Head == NULL) {
  341. EtwpLeavePMCritSection();
  342. return NULL;
  343. }
  344. Next = Head->Flink;
  345. while (Next != Head) {
  346. pEntry = CONTAINING_RECORD( Next, TRACELOG_CONTEXT, Entry );
  347. Next = Next->Flink;
  348. if (TraceHandle == pEntry->TraceHandle) {
  349. EtwpLeavePMCritSection();
  350. return pEntry;
  351. }
  352. }
  353. EtwpLeavePMCritSection();
  354. return NULL;
  355. }
  356. ULONG
  357. EtwpFreeTraceHandle(
  358. TRACEHANDLE TraceHandle
  359. )
  360. {
  361. PLIST_ENTRY Head, Next;
  362. PTRACELOG_CONTEXT pEntry;
  363. EtwpEnterPMCritSection();
  364. Head = TraceHandleListHeadPtr;
  365. if (Head == NULL) {
  366. EtwpLeavePMCritSection();
  367. return ERROR_INVALID_HANDLE;
  368. }
  369. Next = Head->Flink;
  370. while (Next != Head) {
  371. pEntry = CONTAINING_RECORD( Next, TRACELOG_CONTEXT, Entry );
  372. Next = Next->Flink;
  373. if (TraceHandle == pEntry->TraceHandle) {
  374. //
  375. // This test prevents someone calling CloseTrace on a Handle
  376. // while another thread is busy executing ProcessTrace on the
  377. // same handle.
  378. // TODO: We could implement a RefCount approach which would
  379. // allow this to succeed but ProcessTrace will cleanup if
  380. // someone has already called CloseTrace?
  381. //
  382. //
  383. if (pEntry->fProcessed == TRUE)
  384. {
  385. EtwpLeavePMCritSection();
  386. return ERROR_BUSY;
  387. }
  388. RemoveEntryList(&pEntry->Entry);
  389. // Free pEntry memory
  390. //
  391. if (pEntry->Logfile.LogFileName != NULL)
  392. {
  393. EtwpFree(pEntry->Logfile.LogFileName);
  394. }
  395. if (pEntry->Logfile.LoggerName != NULL)
  396. {
  397. EtwpFree(pEntry->Logfile.LoggerName);
  398. }
  399. CloseHandle(pEntry->AsynchRead.hEvent);
  400. EtwpFree(pEntry);
  401. //
  402. // If the handle list is empty, then delete it.
  403. //
  404. if (Head == Head->Flink) {
  405. EtwpFree(TraceHandleListHeadPtr);
  406. TraceHandleListHeadPtr = NULL;
  407. }
  408. EtwpLeavePMCritSection();
  409. return ERROR_SUCCESS;
  410. }
  411. }
  412. EtwpLeavePMCritSection();
  413. return ERROR_INVALID_HANDLE;
  414. }
  415. ULONG
  416. WMIAPI
  417. EtwpCreateGuidMapping(void)
  418. /*++
  419. Routine Description:
  420. This routine is used to create the mapping array between GroupTypes and Guid
  421. for kernel events.
  422. Arguments:
  423. None.
  424. Returned Value:
  425. None
  426. --*/
  427. {
  428. ULONG i = 0;
  429. ULONG listsize;
  430. EtwpEnterPMCritSection();
  431. if (EventMapList == NULL) {
  432. listsize = sizeof(TRACE_GUID_MAP) * MAX_KERNEL_TRACE_EVENTS;
  433. EventMapList = (PTRACE_GUID_MAP) HeapAlloc(GetProcessHeap(),
  434. HEAP_ZERO_MEMORY,
  435. listsize);
  436. if (EventMapList == NULL) {
  437. EtwpLeavePMCritSection();
  438. return EtwpSetDosError(ERROR_OUTOFMEMORY);
  439. }
  440. EventMapList[i].GroupType = EVENT_TRACE_GROUP_IO;
  441. RtlCopyMemory(&EventMapList[i++].Guid,&DiskIoGuid, sizeof(GUID));
  442. EventMapList[i].GroupType = EVENT_TRACE_GROUP_FILE;
  443. RtlCopyMemory(&EventMapList[i++].Guid, &FileIoGuid, sizeof(GUID));
  444. EventMapList[i].GroupType = EVENT_TRACE_GROUP_TCPIP;
  445. RtlCopyMemory(&EventMapList[i++].Guid, &TcpIpGuid, sizeof(GUID));
  446. EventMapList[i].GroupType = EVENT_TRACE_GROUP_UDPIP;
  447. RtlCopyMemory(&EventMapList[i++].Guid, &UdpIpGuid, sizeof(GUID));
  448. EventMapList[i].GroupType = EVENT_TRACE_GROUP_THREAD;
  449. RtlCopyMemory(&EventMapList[i++].Guid, &ThreadGuid, sizeof(GUID));
  450. EventMapList[i].GroupType = EVENT_TRACE_GROUP_PROCESS;
  451. RtlCopyMemory(&EventMapList[i++].Guid, &ProcessGuid, sizeof(GUID));
  452. EventMapList[i].GroupType = EVENT_TRACE_GROUP_MEMORY;
  453. RtlCopyMemory(&EventMapList[i++].Guid, &PageFaultGuid, sizeof(GUID));
  454. EventMapList[i].GroupType = EVENT_TRACE_GROUP_HEADER;
  455. RtlCopyMemory(&EventMapList[i++].Guid, &EventTraceGuid, sizeof(GUID));
  456. EventMapList[i].GroupType = EVENT_TRACE_GROUP_PROCESS +
  457. EVENT_TRACE_TYPE_LOAD;
  458. RtlCopyMemory(&EventMapList[i++].Guid, &ImageLoadGuid, sizeof(GUID));
  459. EventMapList[i].GroupType = EVENT_TRACE_GROUP_REGISTRY;
  460. RtlCopyMemory(&EventMapList[i++].Guid, &RegistryGuid, sizeof(GUID));
  461. EventMapList[i].GroupType = EVENT_TRACE_GROUP_DBGPRINT;
  462. RtlCopyMemory(&EventMapList[i++].Guid, &DbgPrintGuid, sizeof(GUID));
  463. EventMapList[i].GroupType = EVENT_TRACE_GROUP_CONFIG;
  464. RtlCopyMemory(&EventMapList[i++].Guid, &EventTraceConfigGuid, sizeof(GUID));
  465. EventMapList[i].GroupType = EVENT_TRACE_GROUP_POOL;
  466. RtlCopyMemory(&EventMapList[i++].Guid, &PoolGuid, sizeof(GUID));
  467. EventMapList[i].GroupType = EVENT_TRACE_GROUP_PERFINFO;
  468. RtlCopyMemory(&EventMapList[i++].Guid, &PerfinfoGuid, sizeof(GUID));
  469. EventMapList[i].GroupType = EVENT_TRACE_GROUP_HEAP;
  470. RtlCopyMemory(&EventMapList[i++].Guid, &HeapGuid, sizeof(GUID));
  471. EventMapList[i].GroupType = EVENT_TRACE_GROUP_OBJECT;
  472. RtlCopyMemory(&EventMapList[i++].Guid, &ObjectGuid, sizeof(GUID));
  473. EventMapList[i].GroupType = EVENT_TRACE_GROUP_MODBOUND;
  474. RtlCopyMemory(&EventMapList[i++].Guid, &ModBoundGuid, sizeof(GUID));
  475. EventMapList[i].GroupType = EVENT_TRACE_GROUP_DPC;
  476. RtlCopyMemory(&EventMapList[i++].Guid, &DpcGuid, sizeof(GUID));
  477. EventMapList[i].GroupType = EVENT_TRACE_GROUP_POWER;
  478. RtlCopyMemory(&EventMapList[i++].Guid, &PowerGuid, sizeof(GUID));
  479. EventMapList[i].GroupType = EVENT_TRACE_GROUP_CRITSEC;
  480. RtlCopyMemory(&EventMapList[i++].Guid, &CritSecGuid, sizeof(GUID));
  481. }
  482. EtwpLeavePMCritSection();
  483. return EtwpSetDosError(ERROR_SUCCESS);
  484. }
  485. LPGUID
  486. EtwpGuidMapHandleToGuid(
  487. PLIST_ENTRY GuidMapListHeadPtr,
  488. ULONGLONG GuidHandle
  489. )
  490. {
  491. PLIST_ENTRY Next, Head;
  492. PEVENT_GUID_MAP GuidMap;
  493. ULONG retry_count=0;
  494. EtwpEnterPMCritSection();
  495. Head = GuidMapListHeadPtr;
  496. Next = Head->Flink;
  497. while (Next != Head) {
  498. GuidMap = CONTAINING_RECORD( Next, EVENT_GUID_MAP, Entry );
  499. if (GuidMap->GuidHandle == GuidHandle) {
  500. EtwpLeavePMCritSection();
  501. return (&GuidMap->Guid);
  502. }
  503. Next = Next->Flink;
  504. }
  505. EtwpLeavePMCritSection();
  506. return NULL;
  507. }
  508. ULONG
  509. EtwpAddGuidHandleToGuidMapList(
  510. IN PLIST_ENTRY GuidMapListHeadPtr,
  511. IN ULONGLONG GuidHandle,
  512. IN LPGUID Guid
  513. )
  514. {
  515. PEVENT_GUID_MAP GuidMap;
  516. if (GuidMapListHeadPtr != NULL) {
  517. GuidMap = EtwpAlloc(sizeof(EVENT_GUID_MAP));
  518. if (GuidMap == NULL)
  519. return EtwpSetDosError(ERROR_OUTOFMEMORY);
  520. RtlZeroMemory(GuidMap, sizeof(EVENT_GUID_MAP));
  521. GuidMap->GuidHandle = GuidHandle;
  522. GuidMap->Guid = *Guid;
  523. EtwpEnterPMCritSection();
  524. InsertTailList(GuidMapListHeadPtr, &GuidMap->Entry);
  525. EtwpLeavePMCritSection();
  526. }
  527. return EtwpSetDosError(ERROR_SUCCESS);
  528. }
  529. void
  530. EtwpCleanupGuidMapList(
  531. PLIST_ENTRY GuidMapListHeadPtr
  532. )
  533. {
  534. EtwpEnterPMCritSection();
  535. if (GuidMapListHeadPtr != NULL) {
  536. PLIST_ENTRY Next, Head;
  537. PEVENT_GUID_MAP GuidMap;
  538. Head = GuidMapListHeadPtr;
  539. Next = Head->Flink;
  540. while (Next != Head) {
  541. GuidMap = CONTAINING_RECORD( Next, EVENT_GUID_MAP, Entry );
  542. Next = Next->Flink;
  543. RemoveEntryList(&GuidMap->Entry);
  544. EtwpFree(GuidMap);
  545. }
  546. GuidMapListHeadPtr = NULL;
  547. }
  548. EtwpLeavePMCritSection();
  549. }
  550. void
  551. EtwpCleanupStreamList(
  552. PLIST_ENTRY StreamListHeadPtr
  553. )
  554. {
  555. PLIST_ENTRY Next, Head;
  556. PTRACE_STREAM_CONTEXT pStream;
  557. if (StreamListHeadPtr != NULL) {
  558. Head = StreamListHeadPtr;
  559. Next = Head->Flink;
  560. while(Next != Head) {
  561. pStream = CONTAINING_RECORD(Next, TRACE_STREAM_CONTEXT, AllocEntry);
  562. Next = Next->Flink;
  563. RemoveEntryList(&pStream->AllocEntry);
  564. if (pStream->StreamBuffer != NULL) {
  565. EtwpFree(pStream->StreamBuffer);
  566. }
  567. if (ETW_LOG_BUFFER()) {
  568. DbgPrint("ETW: Stream %d Proc %d Received %d Events\n",
  569. pStream->Type, pStream->ProcessorNumber, pStream->CbCount);
  570. }
  571. EtwpFree(pStream);
  572. }
  573. }
  574. }
  575. VOID
  576. EtwpFreeCallbackList()
  577. /*++
  578. Routine Description:
  579. This routine removes all event callbacks and frees the storage.
  580. Arguments:
  581. None
  582. Returned Value:
  583. None.
  584. --*/
  585. {
  586. PLIST_ENTRY Next, Head;
  587. PEVENT_TRACE_CALLBACK EventCb;
  588. if (EventCallbackListHead == NULL)
  589. return;
  590. EtwpEnterPMCritSection();
  591. Head = EventCallbackListHead;
  592. Next = Head->Flink;
  593. while (Next != Head) {
  594. EventCb = CONTAINING_RECORD( Next, EVENT_TRACE_CALLBACK, Entry );
  595. Next = Next->Flink;
  596. RemoveEntryList(&EventCb->Entry);
  597. EtwpFree(EventCb);
  598. }
  599. EtwpFree(EventCallbackListHead);
  600. EventCallbackListHead = NULL;
  601. EtwpLeavePMCritSection();
  602. }
  603. PEVENT_TRACE_CALLBACK
  604. EtwpGetCallbackRoutine(
  605. LPGUID pGuid
  606. )
  607. /*++
  608. Routine Description:
  609. This routine returns the callback function for a given Guid.
  610. If no callback was registered for the Guid, returns NULL.
  611. Arguments:
  612. pGuid pointer to the Guid.
  613. Returned Value:
  614. Event Trace Callback Function.
  615. --*/
  616. {
  617. PLIST_ENTRY head, next;
  618. PEVENT_TRACE_CALLBACK pEventCb = NULL;
  619. if (pGuid == NULL)
  620. return NULL;
  621. EtwpEnterPMCritSection();
  622. if (EventCallbackListHead == NULL) {
  623. EtwpLeavePMCritSection();
  624. return NULL;
  625. }
  626. head = EventCallbackListHead;
  627. next = head->Flink;
  628. while (next != head) {
  629. pEventCb = CONTAINING_RECORD( next, EVENT_TRACE_CALLBACK, Entry);
  630. if (IsEqualGUID(pGuid, &pEventCb->Guid)) {
  631. EtwpLeavePMCritSection();
  632. return (pEventCb);
  633. }
  634. next = next->Flink;
  635. }
  636. EtwpLeavePMCritSection();
  637. return NULL;
  638. }
  639. ULONG
  640. WMIAPI
  641. SetTraceCallback(
  642. IN LPCGUID pGuid,
  643. IN PEVENT_CALLBACK EventCallback
  644. )
  645. /*++
  646. Routine Description:
  647. This routine is used to wire a callback function for Guid. The
  648. callback function is called when an Event with this Guid is found in
  649. the subsequent ProcessTraceLog Call.
  650. Arguments:
  651. pGuid Pointer to the Guid.
  652. func Callback Function Address.
  653. Return Value:
  654. ERROR_SUCCESS Callback function is wired
  655. --*/
  656. {
  657. PEVENT_TRACE_CALLBACK pEventCb;
  658. PLIST_ENTRY head, next;
  659. GUID FilterGuid;
  660. ULONG Checksum;
  661. ULONG Status;
  662. EtwpInitProcessHeap();
  663. if ((pGuid == NULL) || (EventCallback == NULL) ||
  664. (EventCallback == (PEVENT_CALLBACK) -1 ) ) {
  665. return EtwpSetDosError(ERROR_INVALID_PARAMETER);
  666. }
  667. //
  668. // Capture the Guid first. We try to access the first ULONG of the
  669. // function address to see if AV.
  670. // TODO: Perhaps we should check to see if it's a valid user mode address.
  671. //
  672. try {
  673. FilterGuid = *pGuid;
  674. Checksum = *((PULONG)EventCallback);
  675. if (Checksum) {
  676. Status = Checksum;
  677. }
  678. }
  679. except (EXCEPTION_EXECUTE_HANDLER) {
  680. return EtwpSetDosError(ERROR_NOACCESS);
  681. }
  682. EtwpEnterPMCritSection();
  683. if (EventCallbackListHead == NULL) {
  684. EventCallbackListHead = (PLIST_ENTRY) EtwpAlloc(sizeof(LIST_ENTRY));
  685. if (EventCallbackListHead == NULL) {
  686. EtwpLeavePMCritSection();
  687. return EtwpSetDosError(ERROR_OUTOFMEMORY);
  688. }
  689. InitializeListHead(EventCallbackListHead);
  690. }
  691. //
  692. // If there is a callback wired for this Guid, simply update the function.
  693. //
  694. head = EventCallbackListHead;
  695. next = head->Flink;
  696. while (next != head) {
  697. pEventCb = CONTAINING_RECORD( next, EVENT_TRACE_CALLBACK, Entry);
  698. if (IsEqualGUID(&FilterGuid, &pEventCb->Guid)) {
  699. pEventCb->CallbackRoutine = EventCallback;
  700. EtwpLeavePMCritSection();
  701. return EtwpSetDosError(ERROR_SUCCESS);
  702. }
  703. next = next->Flink;
  704. }
  705. //
  706. // Create a new entry in the EventCallbackList for this Guid.
  707. //
  708. pEventCb = (PEVENT_TRACE_CALLBACK) EtwpAlloc (sizeof(EVENT_TRACE_CALLBACK));
  709. if (pEventCb == NULL) {
  710. EtwpLeavePMCritSection();
  711. return EtwpSetDosError(ERROR_OUTOFMEMORY);
  712. }
  713. RtlZeroMemory(pEventCb, sizeof(EVENT_TRACE_CALLBACK));
  714. pEventCb->Guid = FilterGuid;
  715. pEventCb->CallbackRoutine = EventCallback;
  716. InsertTailList(EventCallbackListHead, &pEventCb->Entry);
  717. EtwpLeavePMCritSection();
  718. Status = ERROR_SUCCESS;
  719. return EtwpSetDosError(Status);
  720. }
  721. ULONG
  722. WMIAPI
  723. RemoveTraceCallback(
  724. IN LPCGUID pGuid
  725. )
  726. /*++
  727. Routine Description:
  728. This routine removes a callback function for a given Guid.
  729. Arguments:
  730. pGuid Pointer to the Guid for which the callback routine needs
  731. to be deleted.
  732. Return Value:
  733. ERROR_SUCCESS Successfully deleted the callback routine.
  734. ERROR_INVALID_PARAMETER Could not find any callbacks for the Guid.
  735. --*/
  736. {
  737. PLIST_ENTRY next, head;
  738. PEVENT_TRACE_CALLBACK EventCb;
  739. GUID RemoveGuid;
  740. ULONG errorCode;
  741. EtwpInitProcessHeap();
  742. if ((pGuid == NULL) || (EventCallbackListHead == NULL))
  743. return EtwpSetDosError(ERROR_INVALID_PARAMETER);
  744. //
  745. // Capture the Guid into a local variable first
  746. //
  747. try {
  748. RemoveGuid = *pGuid;
  749. }
  750. except (EXCEPTION_EXECUTE_HANDLER) {
  751. return EtwpSetDosError(ERROR_NOACCESS);
  752. }
  753. errorCode = ERROR_WMI_GUID_NOT_FOUND;
  754. EtwpEnterPMCritSection();
  755. head = EventCallbackListHead;
  756. next = head->Flink;
  757. while (next != head) {
  758. EventCb = CONTAINING_RECORD( next, EVENT_TRACE_CALLBACK, Entry);
  759. next = next->Flink;
  760. if (IsEqualGUID(&EventCb->Guid, &RemoveGuid)) {
  761. RemoveEntryList(&EventCb->Entry);
  762. EtwpFree(EventCb);
  763. errorCode = ERROR_SUCCESS;
  764. }
  765. }
  766. EtwpLeavePMCritSection();
  767. return EtwpSetDosError(errorCode);
  768. }
  769. #ifdef DBG
  770. void
  771. EtwpDumpEvent(
  772. PEVENT_TRACE pEvent
  773. )
  774. {
  775. DbgPrint("\tSize %d\n", pEvent->Header.Size);
  776. DbgPrint("\tThreadId %X\n", pEvent->Header.ThreadId);
  777. DbgPrint("\tTime Stamp %I64u\n", pEvent->Header.TimeStamp.QuadPart);
  778. }
  779. void
  780. EtwpDumpGuid(
  781. LPGUID pGuid
  782. )
  783. {
  784. DbgPrint("Guid=%x,%x,%x,\n\t{%x,%x,%x,%x,%x,%x,%x}\n",
  785. pGuid->Data1, pGuid->Data2, pGuid->Data3,
  786. pGuid->Data4[0], pGuid->Data4[1], pGuid->Data4[2], pGuid->Data4[3],
  787. pGuid->Data4[5], pGuid->Data4[6], pGuid->Data4[7], pGuid->Data4[8]);
  788. }
  789. void EtwpDumpCallbacks()
  790. {
  791. PLIST_ENTRY next, head;
  792. PEVENT_TRACE_CALLBACK EventCb;
  793. if (EventCallbackListHead == NULL)
  794. return;
  795. EtwpEnterPMCritSection();
  796. head = EventCallbackListHead;
  797. next = head->Flink;
  798. while (next != head) {
  799. EventCb = CONTAINING_RECORD(next, EVENT_TRACE_CALLBACK, Entry);
  800. EtwpDumpGuid(&EventCb->Guid);
  801. next = next->Flink;
  802. }
  803. EtwpLeavePMCritSection();
  804. }
  805. #endif
  806. ULONG
  807. EtwpReadGuidMapRecords(
  808. PEVENT_TRACE_LOGFILEW logfile,
  809. PVOID pBuffer,
  810. BOOLEAN bLogFileHeader
  811. )
  812. {
  813. PEVENT_TRACE pEvent;
  814. EVENT_TRACE EventTrace;
  815. ULONG BufferSize;
  816. ULONG Status;
  817. WMI_HEADER_TYPE HeaderType = WMIHT_NONE;
  818. ULONG Size;
  819. ULONG Offset;
  820. PTRACELOG_CONTEXT pContext = logfile->Context;
  821. Offset = sizeof(WMI_BUFFER_HEADER);
  822. while (TRUE) {
  823. pEvent = &EventTrace;
  824. RtlZeroMemory(pEvent, sizeof(EVENT_TRACE) );
  825. HeaderType = WmiGetTraceHeader(pBuffer, Offset, &Size);
  826. if ( (HeaderType == WMIHT_NONE) ||
  827. (HeaderType == WMIHT_WNODE) ||
  828. (Size == 0)
  829. ) {
  830. break;
  831. }
  832. Status = EtwpParseTraceEvent(pContext, pBuffer, Offset, HeaderType, pEvent, sizeof(EVENT_TRACE));
  833. Offset += Size;
  834. if (IsEqualGUID(&pEvent->Header.Guid, &EventTraceGuid)
  835. && (pEvent->Header.Class.Type == EVENT_TRACE_TYPE_GUIDMAP))
  836. {
  837. EtwpGuidMapCallback(&pContext->GuidMapListHead, pEvent);
  838. //
  839. // If we are processing the events in raw base pointer mode,
  840. // we fire callbacks for guid maps also. Note that only the
  841. // GuidMaps at the start of the file are triggered. The ones at the
  842. // end are ignored. This is because the time order needs to be
  843. // preserved when firing callbacks to the user.
  844. //
  845. if (bLogFileHeader && (pContext->ConversionFlags & EVENT_TRACE_GET_RAWEVENT)) {
  846. PTRACE_LOGFILE_HEADER pLogHeader = (PTRACE_LOGFILE_HEADER)(pEvent->MofData);
  847. pLogHeader->LoggerName = (LPWSTR)((PUCHAR)pLogHeader + sizeof(TRACE_LOGFILE_HEADER));
  848. pLogHeader->LogFileName = (LPWSTR)((PUCHAR)pLogHeader + sizeof(TRACE_LOGFILE_HEADER)
  849. + (wcslen(pLogHeader->LoggerName) + 1) * sizeof(WCHAR));
  850. Status = EtwpDoEventCallbacks( logfile, pEvent);
  851. if (Status != ERROR_SUCCESS) {
  852. break;
  853. }
  854. }
  855. }
  856. else {
  857. if (bLogFileHeader) {
  858. PTRACE_LOGFILE_HEADER pLogHeader = (PTRACE_LOGFILE_HEADER)(pEvent->MofData);
  859. pLogHeader->LoggerName = (LPWSTR)((PUCHAR)pLogHeader + sizeof(TRACE_LOGFILE_HEADER));
  860. pLogHeader->LogFileName = (LPWSTR)((PUCHAR)pLogHeader + sizeof(TRACE_LOGFILE_HEADER)
  861. + (wcslen(pLogHeader->LoggerName) + 1) * sizeof(WCHAR));
  862. Status = EtwpDoEventCallbacks( logfile, pEvent);
  863. if (Status != ERROR_SUCCESS) {
  864. break;
  865. }
  866. }
  867. else {
  868. return ERROR_INVALID_DATA;
  869. }
  870. }
  871. }
  872. return ERROR_SUCCESS;
  873. }
  874. ULONG
  875. EtwpProcessGuidMaps(
  876. PEVENT_TRACE_LOGFILEW *Logfiles,
  877. ULONG LogfileCount,
  878. ULONG Unicode
  879. )
  880. {
  881. long i;
  882. NTSTATUS Status;
  883. PTRACELOG_CONTEXT pContext;
  884. PEVENT_TRACE_LOGFILEW logfile;
  885. ULONG BuffersWritten;
  886. ULONG BufferSize;
  887. ULONG nBytesRead=0;
  888. ULONGLONG SizeWritten, ReadPosition;
  889. PVOID pBuffer;
  890. for (i=0; i<(long)LogfileCount; i++) {
  891. logfile = Logfiles[i];
  892. if (Logfiles[i]->LogFileMode & EVENT_TRACE_REAL_TIME_MODE) {
  893. continue;
  894. }
  895. if (logfile->IsKernelTrace) {
  896. continue;
  897. }
  898. pContext = (PTRACELOG_CONTEXT) logfile->Context;
  899. if (pContext == NULL) {
  900. continue;
  901. }
  902. //
  903. // We now start reading the GuidMaps at the end of file.
  904. //
  905. if (!(Logfiles[i]->LogFileMode & EVENT_TRACE_FILE_MODE_CIRCULAR))
  906. {
  907. pContext->fGuidMapRead = FALSE;
  908. }
  909. BuffersWritten = logfile->LogfileHeader.BuffersWritten;
  910. BufferSize = pContext->BufferSize;
  911. SizeWritten = BuffersWritten * BufferSize;
  912. if (Logfiles[i]->LogFileMode & EVENT_TRACE_FILE_MODE_CIRCULAR) {
  913. ULONGLONG maxFileSize = (logfile->LogfileHeader.MaximumFileSize
  914. * 1024 * 1024);
  915. if ( (maxFileSize > 0) && (SizeWritten > maxFileSize) ) {
  916. SizeWritten = maxFileSize;
  917. }
  918. }
  919. pBuffer = EtwpAlloc(BufferSize);
  920. if (pBuffer == NULL) {
  921. return EtwpSetDosError(ERROR_OUTOFMEMORY);
  922. }
  923. RtlZeroMemory(pBuffer, BufferSize);
  924. ReadPosition = SizeWritten;
  925. while (TRUE) {
  926. if (!GetOverlappedResult(pContext->Handle, &pContext->AsynchRead, &nBytesRead, TRUE) &&
  927. GetLastError() != ERROR_HANDLE_EOF) {
  928. EtwpDebugPrint(("GetOverlappedResult failed with Status %d in ProcessGuidMaps\n", GetLastError()));
  929. break;
  930. }
  931. pContext->AsynchRead.Offset = (DWORD)(ReadPosition & 0xFFFFFFFF);
  932. pContext->AsynchRead.OffsetHigh = (DWORD)(ReadPosition >> 32);
  933. Status = EtwpSynchReadFile(pContext->Handle,
  934. (LPVOID)pBuffer,
  935. BufferSize,
  936. &nBytesRead,
  937. &pContext->AsynchRead);
  938. if (nBytesRead == 0) {
  939. break;
  940. }
  941. Status = EtwpReadGuidMapRecords(Logfiles[i], pBuffer, FALSE);
  942. if (Status != ERROR_SUCCESS) {
  943. break;
  944. }
  945. ReadPosition += BufferSize;
  946. }
  947. //
  948. // End of File was reached. Now set the File Pointer back to
  949. // the top of the file and process it.
  950. pContext->StartBuffer = 0;
  951. ReadPosition = 0;
  952. while (TRUE) {
  953. BOOLEAN bLogFileHeader;
  954. if (!GetOverlappedResult(pContext->Handle, &pContext->AsynchRead, &nBytesRead, TRUE) &&
  955. GetLastError() != ERROR_HANDLE_EOF) {
  956. EtwpDebugPrint(("GetOverlappedResult failed with Status %d in ProcessGuidMaps\n", GetLastError()));
  957. break;
  958. }
  959. pContext->AsynchRead.Offset = (DWORD)(ReadPosition & 0xFFFFFFFF);
  960. pContext->AsynchRead.OffsetHigh = (DWORD)(ReadPosition >> 32);
  961. Status = EtwpSynchReadFile(pContext->Handle,
  962. (LPVOID)pBuffer,
  963. BufferSize,
  964. &nBytesRead,
  965. &pContext->AsynchRead);
  966. if (nBytesRead == 0) {
  967. break;
  968. }
  969. bLogFileHeader = (pContext->StartBuffer == 0);
  970. Status = EtwpReadGuidMapRecords(Logfiles[i], pBuffer, bLogFileHeader );
  971. if (Status != ERROR_SUCCESS){
  972. break;
  973. }
  974. pContext->StartBuffer++;
  975. ReadPosition += BufferSize;
  976. }
  977. EtwpFree(pBuffer);
  978. }
  979. return ERROR_SUCCESS;
  980. }
  981. ULONG
  982. EtwpGetBuffersWrittenFromQuery(
  983. LPWSTR LoggerName
  984. )
  985. /*++
  986. Routine Description:
  987. This routine returns the number of buffers written by querying a logger.
  988. In case of an array of LogFiles, this routine should be called individually for
  989. each one.
  990. Arguments:
  991. LogFile - pointer to EVENT_TRACE_LOGFILEW under consideration
  992. Unicode - whether the logger name is in unicode or not
  993. Returned Value:
  994. The number of buffers written.
  995. --*/
  996. {
  997. TRACEHANDLE LoggerHandle = 0;
  998. ULONG Status;
  999. RtlZeroMemory(&QueryProperties, sizeof(QueryProperties));
  1000. QueryProperties.TraceProp.Wnode.BufferSize = sizeof(QueryProperties);
  1001. Status = EtwControlTraceW(LoggerHandle,
  1002. LoggerName,
  1003. &QueryProperties.TraceProp,
  1004. EVENT_TRACE_CONTROL_QUERY);
  1005. if (Status == ERROR_SUCCESS) {
  1006. return QueryProperties.TraceProp.BuffersWritten;
  1007. }
  1008. else {
  1009. SetLastError(Status);
  1010. return 0;
  1011. }
  1012. }
  1013. VOID
  1014. EtwpCopyLogHeader (
  1015. IN PTRACE_LOGFILE_HEADER pOutHeader,
  1016. IN PVOID MofData,
  1017. IN ULONG MofLength,
  1018. IN PWCHAR *LoggerName,
  1019. IN PWCHAR *LogFileName,
  1020. IN ULONG Unicode
  1021. )
  1022. {
  1023. PUCHAR Src, Dest;
  1024. PTRACE_LOGFILE_HEADER pInHeader;
  1025. ULONG PointerSize;
  1026. ULONG SizeToCopy;
  1027. ULONG Offset;
  1028. pInHeader = (PTRACE_LOGFILE_HEADER) MofData;
  1029. PointerSize = pInHeader->PointerSize; // This is the PointerSize in File
  1030. if ( (PointerSize != 4) && (PointerSize != 8) ) {
  1031. #ifdef DBG
  1032. EtwpDebugPrint(("WMI: Invalid PointerSize in File %d\n",PointerSize));
  1033. #endif
  1034. return;
  1035. }
  1036. //
  1037. // We have Two pointers (LPWSTR) in the middle of the LOGFILE_HEADER
  1038. // structure. So We copy upto the Pointer Fields first, skip over
  1039. // the pointers and copy the remaining stuff. We come back and fixup
  1040. // the pointers appropriately.
  1041. //
  1042. SizeToCopy = FIELD_OFFSET(TRACE_LOGFILE_HEADER, LoggerName);
  1043. RtlCopyMemory(pOutHeader, pInHeader, SizeToCopy);
  1044. //
  1045. // Skip over the Troublesome pointers in both Src and Dest
  1046. //
  1047. Dest = (PUCHAR)pOutHeader + SizeToCopy + 2 * sizeof(LPWSTR);
  1048. Src = (PUCHAR)pInHeader + SizeToCopy + 2 * PointerSize;
  1049. //
  1050. // Copy the Remaining fields at the tail end of the LOGFILE_HEADER
  1051. //
  1052. SizeToCopy = sizeof(TRACE_LOGFILE_HEADER) -
  1053. FIELD_OFFSET(TRACE_LOGFILE_HEADER, TimeZone);
  1054. RtlCopyMemory(Dest, Src, SizeToCopy);
  1055. //
  1056. // Adjust the pointer fields now
  1057. //
  1058. Offset = sizeof(TRACE_LOGFILE_HEADER) -
  1059. 2 * sizeof(LPWSTR) +
  1060. 2 * PointerSize;
  1061. *LoggerName = (PWCHAR) ((PUCHAR)pInHeader + Offset);
  1062. pOutHeader->LoggerName = *LoggerName;
  1063. }
  1064. ULONG
  1065. EtwpProcessLogHeader(
  1066. PTRACEHANDLE HandleArray,
  1067. PEVENT_TRACE_LOGFILEW *Logfiles,
  1068. ULONG LogfileCount,
  1069. ULONG Unicode,
  1070. ULONG bFree
  1071. )
  1072. /*++
  1073. Routine Description:
  1074. This routine processes the header of an array of logfiles.
  1075. Arguments:
  1076. LogFile Array of Logfiles being processed.
  1077. LogFileCount Number of Logfiles in the Array.
  1078. Unicode Unicode Flag.
  1079. Returned Value:
  1080. Status Code.
  1081. --*/
  1082. {
  1083. HANDLE hFile;
  1084. PTRACELOG_CONTEXT pContext = NULL;
  1085. PVOID pBuffer;
  1086. PEVENT_TRACE pEvent;
  1087. long i;
  1088. WMI_HEADER_TYPE HeaderType = WMIHT_NONE;
  1089. ULONG Size;
  1090. ULONG Offset;
  1091. LPWSTR loggerName, logFileName;
  1092. ULONG BufferSize, nBytesRead;
  1093. PTRACE_LOGFILE_HEADER logfileHeader;
  1094. ULONG Status = ERROR_SUCCESS;
  1095. //
  1096. // Open the Log File for shared Read
  1097. //
  1098. BufferSize = DEFAULT_LOG_BUFFER_SIZE; // Log file header must be smaller than 1K
  1099. pBuffer = EtwpAlloc(BufferSize);
  1100. if (pBuffer == NULL) {
  1101. return EtwpSetDosError(ERROR_OUTOFMEMORY);
  1102. }
  1103. for (i=0; i<(long)LogfileCount; i++) {
  1104. EVENT_TRACE EventTrace;
  1105. OVERLAPPED LogHeaderOverlapped;
  1106. //
  1107. // Caller can pass in Flags to fetch the timestamps in raw mode.
  1108. // Since LogFileHeader gets overwritten from with data from the logfile
  1109. // we need to save the passed in value here.
  1110. //
  1111. if (Unicode) {
  1112. hFile = CreateFileW(
  1113. (LPWSTR) Logfiles[i]->LogFileName,
  1114. GENERIC_READ,
  1115. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1116. NULL,
  1117. OPEN_EXISTING,
  1118. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
  1119. NULL
  1120. );
  1121. }
  1122. else {
  1123. hFile = CreateFileA(
  1124. (LPSTR) Logfiles[i]->LogFileName,
  1125. GENERIC_READ,
  1126. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1127. NULL,
  1128. OPEN_EXISTING,
  1129. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
  1130. NULL
  1131. );
  1132. }
  1133. if (hFile == INVALID_HANDLE_VALUE) {
  1134. Status = EtwpSetDosError(ERROR_BAD_PATHNAME);
  1135. break;
  1136. }
  1137. BufferSize = DEFAULT_LOG_BUFFER_SIZE;
  1138. RtlZeroMemory(pBuffer, BufferSize);
  1139. LogHeaderOverlapped.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
  1140. if (LogHeaderOverlapped.hEvent == NULL) {
  1141. // cannot create event for file read
  1142. break;
  1143. }
  1144. LogHeaderOverlapped.Offset = 0;
  1145. LogHeaderOverlapped.OffsetHigh = 0;
  1146. Status = EtwpSynchReadFile(hFile,
  1147. (LPVOID)pBuffer,
  1148. BufferSize,
  1149. &nBytesRead,
  1150. &LogHeaderOverlapped);
  1151. if (nBytesRead == 0) {
  1152. NtClose(hFile);
  1153. Status = EtwpSetDosError(ERROR_FILE_CORRUPT);
  1154. break;
  1155. }
  1156. CloseHandle(LogHeaderOverlapped.hEvent);
  1157. Offset = sizeof(WMI_BUFFER_HEADER);
  1158. pEvent = &EventTrace;
  1159. RtlZeroMemory(pEvent, sizeof(EVENT_TRACE) );
  1160. HeaderType = WmiGetTraceHeader(pBuffer, Offset, &Size);
  1161. if ( (HeaderType == WMIHT_NONE) ||
  1162. (HeaderType == WMIHT_WNODE) ||
  1163. (Size == 0)
  1164. ) {
  1165. NtClose(hFile);
  1166. Status = EtwpSetDosError(ERROR_FILE_CORRUPT);
  1167. break;
  1168. }
  1169. Status = EtwpParseTraceEvent(NULL, pBuffer, Offset, HeaderType, pEvent, sizeof(EVENT_TRACE));
  1170. Offset += Size;
  1171. //
  1172. // Set up the header structure properly
  1173. //
  1174. if ((Status == ERROR_SUCCESS) && (pEvent->MofLength > 0)) {
  1175. ULONG PointerSize;
  1176. logfileHeader = &Logfiles[i]->LogfileHeader;
  1177. //
  1178. // We are relying on the fact that the PointerSize field
  1179. // will not shift between platforms.
  1180. //
  1181. PointerSize = ((PTRACE_LOGFILE_HEADER)(pEvent->MofData))->PointerSize;
  1182. if (PointerSize == sizeof(PUCHAR) ) {
  1183. RtlCopyMemory(&Logfiles[i]->LogfileHeader, pEvent->MofData,
  1184. sizeof(TRACE_LOGFILE_HEADER));
  1185. loggerName = (LPWSTR) ( (char*)pEvent->MofData +
  1186. sizeof(TRACE_LOGFILE_HEADER) );
  1187. // logFileName = (LPWSTR) ( (char*)pEvent->MofData +
  1188. // sizeof(TRACE_LOGFILE_HEADER) +
  1189. // sizeof(WCHAR)* wcslen(loggerName));
  1190. }
  1191. else {
  1192. //
  1193. // Ugly thunking going on here. Close your eyes...
  1194. //
  1195. EtwpCopyLogHeader(&Logfiles[i]->LogfileHeader,
  1196. pEvent->MofData,
  1197. pEvent->MofLength,
  1198. &loggerName,
  1199. &logFileName,
  1200. Unicode);
  1201. pEvent->MofData = (PVOID)&Logfiles[i]->LogfileHeader;
  1202. }
  1203. }
  1204. else {
  1205. NtClose(hFile);
  1206. Status = EtwpSetDosError(ERROR_FILE_CORRUPT);
  1207. break;
  1208. }
  1209. Logfiles[i]->IsKernelTrace = !wcscmp(loggerName, KERNEL_LOGGER_NAME);
  1210. Logfiles[i]->LogFileMode = (logfileHeader->LogFileMode &
  1211. ~(EVENT_TRACE_REAL_TIME_MODE));
  1212. if (!bFree && (ETW_LOG_ERROR()) ) {
  1213. DbgPrint("ETW: Dumping Logfile Header\n");
  1214. DbgPrint("\tStart Time %I64u\n",
  1215. pEvent->Header.TimeStamp);
  1216. DbgPrint("\tLogger Thread Id %X\n",
  1217. pEvent->Header.ThreadId);
  1218. DbgPrint("\tHeader Size %d\n",
  1219. pEvent->Header.Size);
  1220. DbgPrint("\tBufferSize %d\n",
  1221. logfileHeader->BufferSize);
  1222. DbgPrint("\tVersion %d\n",
  1223. logfileHeader->Version);
  1224. DbgPrint("\t LogFile Format version %d.%d\n",
  1225. logfileHeader->VersionDetail.SubVersion,
  1226. logfileHeader->VersionDetail.SubMinorVersion);
  1227. DbgPrint("\tProviderVersion %d\n",
  1228. logfileHeader->ProviderVersion);
  1229. DbgPrint("\tEndTime %I64u\n",
  1230. logfileHeader->EndTime);
  1231. DbgPrint("\tTimer Resolution %d\n",
  1232. logfileHeader->TimerResolution);
  1233. DbgPrint("\tMaximum File Size %d\n",
  1234. logfileHeader->MaximumFileSize);
  1235. DbgPrint("\tBuffers Written %d\n",
  1236. logfileHeader->BuffersWritten);
  1237. DbgPrint("\tEvents Lost %d\n",
  1238. logfileHeader->EventsLost);
  1239. DbgPrint("\tBuffers Lost %d\n",
  1240. logfileHeader->BuffersLost);
  1241. DbgPrint("\tStart Buffers%d\n",
  1242. logfileHeader->StartBuffers);
  1243. DbgPrint("\tReserved Flags %x\n",
  1244. logfileHeader->ReservedFlags);
  1245. DbgPrint("\tFrequency %I64u\n",
  1246. logfileHeader->PerfFreq.QuadPart);
  1247. DbgPrint("\tLogger Name %ls\n",
  1248. loggerName);
  1249. DbgPrint("\tStartTime %I64u\n",
  1250. logfileHeader->StartTime.QuadPart);
  1251. // DbgPrint("\tLogfile Name %ls\n",
  1252. // logFileName);
  1253. DbgPrint("\tLogfile Mode %X\n",
  1254. logfileHeader->LogFileMode);
  1255. DbgPrint("\tProcessorCount %d\n",
  1256. logfileHeader->NumberOfProcessors);
  1257. DbgPrint("\tETW: IsKernelTrace = %d\n", Logfiles[i]->IsKernelTrace);
  1258. }
  1259. BufferSize = logfileHeader->BufferSize;
  1260. EtwpAssert(BufferSize > 0);
  1261. if ( (BufferSize/1024 == 0) ||
  1262. (((BufferSize/1024)*1024) != BufferSize) ) {
  1263. NtClose(hFile);
  1264. Status = EtwpSetDosError(ERROR_FILE_CORRUPT);
  1265. break;
  1266. }
  1267. if (Logfiles[i]->IsKernelTrace)
  1268. EtwpDebugPrint(("\tLogfile contains kernel trace\n"));
  1269. if (bFree) {
  1270. NtClose(hFile);
  1271. }
  1272. else {
  1273. //
  1274. // At this point, the logfile is opened successfully
  1275. // Initialize the internal context now
  1276. //
  1277. pContext = EtwpLookupTraceHandle(HandleArray[i]);
  1278. if (pContext == NULL) {
  1279. NtClose(hFile);
  1280. Status = EtwpSetDosError(ERROR_OUTOFMEMORY);
  1281. break;
  1282. }
  1283. Logfiles[i]->Context = pContext;
  1284. pContext->Handle = hFile;
  1285. //
  1286. // If this is kernel file with Version 1.2 or above, look for
  1287. // extended logfileheader event.
  1288. //
  1289. if ( (Logfiles[i]->IsKernelTrace) &&
  1290. (logfileHeader->VersionDetail.SubVersion >= 1) &&
  1291. (logfileHeader->VersionDetail.SubMinorVersion >= 2) ) {
  1292. EVENT_TRACE TmpEvent;
  1293. HeaderType = WmiGetTraceHeader(pBuffer, Offset, &Size);
  1294. if ( (HeaderType == WMIHT_NONE) ||
  1295. (HeaderType == WMIHT_WNODE) ||
  1296. (Size == 0)
  1297. ) {
  1298. NtClose(hFile);
  1299. pContext->Handle = NULL;
  1300. Status = EtwpSetDosError(ERROR_FILE_CORRUPT);
  1301. break;
  1302. }
  1303. RtlZeroMemory(&TmpEvent, sizeof(EVENT_TRACE));
  1304. Status = EtwpParseTraceEvent(NULL, pBuffer, Offset, HeaderType,
  1305. &TmpEvent, sizeof(EVENT_TRACE));
  1306. if ((Status == ERROR_SUCCESS) &&
  1307. (TmpEvent.MofLength >= sizeof(PERFINFO_GROUPMASK))) {
  1308. RtlCopyMemory(&pContext->PerfGroupMask, TmpEvent.MofData,
  1309. sizeof(PERFINFO_GROUPMASK) );
  1310. }
  1311. }
  1312. //
  1313. // If the EndTime is 0, then we can not trust the BuffersWritten
  1314. // field in the LogFileHeader. First we query the Logger to get
  1315. // the bufferswritten. However, if the file is being processed
  1316. // from a different machine, then the QueryTrace call could fail.
  1317. // As a second option, we use the FileSize. Note that for loggers
  1318. // with PREALLOCATE file, the filesize is bogus.
  1319. //
  1320. //
  1321. if (logfileHeader->EndTime.QuadPart == 0) {
  1322. logfileHeader->BuffersWritten =
  1323. EtwpGetBuffersWrittenFromQuery(loggerName);
  1324. if (logfileHeader->BuffersWritten == 0) {
  1325. FILE_STANDARD_INFORMATION FileInfo;
  1326. NTSTATUS NtStatus;
  1327. IO_STATUS_BLOCK IoStatus;
  1328. NtStatus = NtQueryInformationFile(
  1329. hFile,
  1330. &IoStatus,
  1331. &FileInfo,
  1332. sizeof(FILE_STANDARD_INFORMATION),
  1333. FileStandardInformation
  1334. );
  1335. if (NT_SUCCESS(NtStatus)) {
  1336. ULONG64 FileSize = FileInfo.AllocationSize.QuadPart;
  1337. ULONG64 FileBuffers = FileSize / (ULONG64) BufferSize;
  1338. logfileHeader->BuffersWritten = (ULONG) FileBuffers;
  1339. }
  1340. if (logfileHeader->BuffersWritten == 0) {
  1341. NtClose(hFile);
  1342. pContext->Handle = NULL;
  1343. Status = EtwpSetDosError(ERROR_FILE_CORRUPT);
  1344. break;
  1345. }
  1346. }
  1347. if (!bFree && (ETW_LOG_ERROR())) {
  1348. DbgPrint("ETW: Set BuffersWritten to %d from QueryTrace\n",
  1349. logfileHeader->BuffersWritten);
  1350. }
  1351. }
  1352. pContext->BufferCount = logfileHeader->BuffersWritten;
  1353. pContext->BufferSize = logfileHeader->BufferSize;
  1354. if ((logfileHeader->LogFileMode & EVENT_TRACE_FILE_MODE_CIRCULAR) &&
  1355. (logfileHeader->MaximumFileSize > 0) ) {
  1356. ULONG maxFileSize = logfileHeader->MaximumFileSize; // in MB
  1357. ULONG StartBuffer = logfileHeader->StartBuffers;
  1358. ULONG maxBuffers = (maxFileSize * 1024 * 1024) / BufferSize;
  1359. ULONG BuffersWritten = logfileHeader->BuffersWritten;
  1360. ULONG FirstBuffer;
  1361. if ((maxBuffers > StartBuffer) && (maxBuffers < BuffersWritten))
  1362. FirstBuffer = StartBuffer + ((BuffersWritten-StartBuffer)
  1363. % (maxBuffers-StartBuffer));
  1364. else
  1365. FirstBuffer = StartBuffer;
  1366. pContext->StartBuffer = StartBuffer;
  1367. pContext->FirstBuffer = FirstBuffer;
  1368. pContext->LastBuffer = maxBuffers;
  1369. if (!bFree && (ETW_LOG_ERROR())) {
  1370. DbgPrint("ETW: Buffers: Start %d First %d Last %d \n",
  1371. StartBuffer, FirstBuffer, maxBuffers);
  1372. }
  1373. }
  1374. //
  1375. // Make the header the current Event ...
  1376. // and the callbacks for the header are handled by ProcessTraceLog.
  1377. pContext->UsePerfClock = logfileHeader->ReservedFlags;
  1378. //
  1379. // If the same structure is used to call OpenTrace again
  1380. // it will lead us to misuse the ReservedFlags as ConversionFlag.
  1381. // To be safe, we restore it here to caller's flags.
  1382. //
  1383. pContext->StartTime = logfileHeader->StartTime;
  1384. pContext->PerfFreq = logfileHeader->PerfFreq;
  1385. pContext->CpuSpeedInMHz = logfileHeader->CpuSpeedInMHz;
  1386. //
  1387. // If the conversion flags are set, adjust UsePerfClock accordingly.
  1388. //
  1389. if (pContext->ConversionFlags & EVENT_TRACE_USE_RAWTIMESTAMP) {
  1390. pContext->UsePerfClock = EVENT_TRACE_CLOCK_RAW;
  1391. }
  1392. if ((pContext->UsePerfClock == EVENT_TRACE_CLOCK_PERFCOUNTER) ||
  1393. (pContext->UsePerfClock == EVENT_TRACE_CLOCK_CPUCYCLE) ) {
  1394. pContext->StartPerfClock = pEvent->Header.TimeStamp;
  1395. Logfiles[i]->CurrentTime = pContext->StartTime.QuadPart;
  1396. pEvent->Header.TimeStamp.QuadPart = pContext->StartTime.QuadPart;
  1397. }
  1398. else {
  1399. Logfiles[i]->CurrentTime = pEvent->Header.TimeStamp.QuadPart;
  1400. }
  1401. }
  1402. }
  1403. EtwpFree(pBuffer);
  1404. return Status;
  1405. }
  1406. ULONG
  1407. EtwpDoEventCallbacks(
  1408. PEVENT_TRACE_LOGFILEW logfile,
  1409. PEVENT_TRACE pEvent
  1410. )
  1411. {
  1412. NTSTATUS Status;
  1413. PEVENT_TRACE_CALLBACK pCallback;
  1414. //
  1415. // First the Generic Event Callback is called.
  1416. //
  1417. if ( logfile->EventCallback ) {
  1418. try {
  1419. (*logfile->EventCallback)(pEvent);
  1420. } except (EXCEPTION_EXECUTE_HANDLER) {
  1421. Status = GetExceptionCode();
  1422. #ifdef DBG
  1423. EtwpDebugPrint(("TRACE: EventCallback threw exception %X\n",
  1424. Status));
  1425. #endif
  1426. return EtwpSetDosError(EtwpNtStatusToDosError(Status));
  1427. }
  1428. }
  1429. //
  1430. // Now Call the event specific callback.
  1431. //
  1432. pCallback = EtwpGetCallbackRoutine( &pEvent->Header.Guid );
  1433. if ( pCallback != NULL ) {
  1434. try {
  1435. (*pCallback->CallbackRoutine)(pEvent);
  1436. } except (EXCEPTION_EXECUTE_HANDLER) {
  1437. Status = GetExceptionCode();
  1438. #ifdef DBG
  1439. EtwpDebugPrint(("EventCallback %X threw exception %X\n",
  1440. pCallback->CallbackRoutine, Status));
  1441. #endif
  1442. return EtwpSetDosError(EtwpNtStatusToDosError(Status));
  1443. }
  1444. }
  1445. logfile->CurrentTime = pEvent->Header.TimeStamp.QuadPart;
  1446. return ERROR_SUCCESS;
  1447. }
  1448. ULONG
  1449. EtwpAdvanceToNewEvent(
  1450. PEVENT_TRACE_LOGFILEW logfile,
  1451. BOOL EventInRange
  1452. )
  1453. {
  1454. ULONG Status = ERROR_SUCCESS;
  1455. PEVENT_TRACE pEvent;
  1456. PTRACELOG_CONTEXT pContext;
  1457. PVOID pBuffer;
  1458. PTRACE_BUFFER_LIST_ENTRY Current;
  1459. ULONG Size;
  1460. WMI_HEADER_TYPE HeaderType = WMIHT_NONE;
  1461. pContext = logfile->Context;
  1462. if (pContext == NULL) {
  1463. return EtwpSetDosError(ERROR_INVALID_PARAMETER);
  1464. }
  1465. Current = EtwpRemoveBuffer(&pContext->Root);
  1466. if (Current == NULL) {
  1467. pContext->EndOfFile = TRUE;
  1468. return ERROR_SUCCESS;
  1469. }
  1470. //
  1471. // Advance Event for current buffer
  1472. //
  1473. pEvent = &Current->Event;
  1474. //
  1475. // Before we make the callbacks, we need to restore the
  1476. // raw buffer, so that MofData will be pointing to the right data.
  1477. //
  1478. pBuffer = EtwpGetCurrentBuffer(pContext, Current);
  1479. if (pBuffer == NULL) {
  1480. //
  1481. // This condition could happen when the file we are reading
  1482. // gets overwritten.
  1483. //
  1484. return ERROR_SHARING_VIOLATION;
  1485. }
  1486. if (EventInRange) {
  1487. Status = EtwpDoEventCallbacks(logfile, pEvent);
  1488. if (Status != ERROR_SUCCESS) {
  1489. return Status;
  1490. }
  1491. }
  1492. Size = 0;
  1493. if ((HeaderType = WmiGetTraceHeader(pBuffer, Current->BufferOffset, &Size)) != WMIHT_NONE) {
  1494. if (Size > 0) {
  1495. Status = EtwpParseTraceEvent(pContext, pBuffer, Current->BufferOffset, HeaderType, pEvent, sizeof(EVENT_TRACE));
  1496. Current->BufferOffset += Size;
  1497. Current->TraceType = EtwpConvertEnumToTraceType(HeaderType);
  1498. }
  1499. }
  1500. Current->EventSize = Size;
  1501. if ( ( Size > 0) && (Status == ERROR_SUCCESS) ) {
  1502. EtwpInsertBuffer(&pContext->Root, Current);
  1503. }
  1504. else {
  1505. DWORD BytesTransffered;
  1506. //
  1507. // When the current buffer is exhausted, make the
  1508. // BufferCallback
  1509. //
  1510. if (logfile->BufferCallback) {
  1511. ULONG bRetVal;
  1512. PWMI_BUFFER_HEADER pHeader = (PWMI_BUFFER_HEADER)pBuffer;
  1513. logfile->Filled = (ULONG)pHeader->Offset;
  1514. logfile->BuffersRead++;
  1515. try {
  1516. bRetVal = (*logfile->BufferCallback) (logfile);
  1517. if (!bRetVal) {
  1518. return ERROR_CANCELLED;
  1519. }
  1520. } except (EXCEPTION_EXECUTE_HANDLER) {
  1521. pContext->EndOfFile = TRUE;
  1522. Status = GetExceptionCode();
  1523. #ifdef DBG
  1524. EtwpDebugPrint(("TRACE: BufferCallback threw exception %X\n",
  1525. Status));
  1526. #endif
  1527. EtwpSetDosError(EtwpNtStatusToDosError(Status));
  1528. return ERROR_CANCELLED; // so that realtime also cleans up.
  1529. }
  1530. }
  1531. //
  1532. // Issue another asynch read on this buffer cache slot if there are no outstanding reads
  1533. // at this point.
  1534. // GetOverlappedResult() returns FALSE if IO is still pending.
  1535. //
  1536. if (pContext->BufferBeingRead == -1 ||
  1537. GetOverlappedResult(pContext->Handle, &pContext->AsynchRead, &BytesTransffered, FALSE)) {
  1538. LONG FileOffset = Current->FileOffset + MAX_TRACE_BUFFER_CACHE_SIZE;
  1539. if ((ULONG)FileOffset < pContext->BufferCount) {
  1540. ULONGLONG Offset = FileOffset * pContext->BufferSize;
  1541. ResetEvent(pContext->AsynchRead.hEvent);
  1542. pContext->AsynchRead.Offset = (DWORD)(Offset & 0xFFFFFFFF);
  1543. pContext->AsynchRead.OffsetHigh = (DWORD)(Offset >> 32);
  1544. Status = ReadFile(pContext->Handle,
  1545. (LPVOID)pBuffer,
  1546. pContext->BufferSize,
  1547. NULL,
  1548. &pContext->AsynchRead);
  1549. if (Status || GetLastError() == ERROR_IO_PENDING) {
  1550. ULONG TableIndex = FileOffset % MAX_TRACE_BUFFER_CACHE_SIZE;
  1551. pContext->BufferBeingRead = FileOffset;
  1552. pContext->BufferCache[TableIndex].Index = FileOffset;
  1553. }
  1554. else { // Issuing asynch IO failed. Not a fatal error. Just continue for now.
  1555. SetEvent(pContext->AsynchRead.hEvent);
  1556. pContext->BufferBeingRead = -1;
  1557. }
  1558. }
  1559. }
  1560. }
  1561. //
  1562. // The File reaches end of file when the Root is NULL
  1563. //
  1564. if (pContext->Root == NULL) {
  1565. pContext->EndOfFile = TRUE;
  1566. }
  1567. else {
  1568. logfile->CurrentTime = pContext->Root->Event.Header.TimeStamp.QuadPart;
  1569. }
  1570. return ERROR_SUCCESS;
  1571. }
  1572. ULONG
  1573. EtwpBuildEventTable(
  1574. PTRACELOG_CONTEXT pContext
  1575. )
  1576. {
  1577. ULONG i, nBytesRead;
  1578. PVOID pBuffer;
  1579. ULONG BufferSize = pContext->BufferSize;
  1580. PEVENT_TRACE pEvent;
  1581. ULONG TotalBuffersRead;
  1582. NTSTATUS Status;
  1583. ULONGLONG ReadPosition;
  1584. //
  1585. // File is already open.
  1586. // Reset the file pointer and continue.
  1587. // TODO: If we start at bottom of file and insert
  1588. // it might be more efficient.
  1589. //
  1590. ReadPosition = pContext->StartBuffer * BufferSize;
  1591. TotalBuffersRead = pContext->StartBuffer;
  1592. //
  1593. // If there are no other buffers except header and guidmaps, EOF is true
  1594. //
  1595. if (TotalBuffersRead == pContext->BufferCount) {
  1596. pContext->EndOfFile = TRUE;
  1597. pContext->Root = NULL;
  1598. return ERROR_SUCCESS;
  1599. }
  1600. do {
  1601. WMI_HEADER_TYPE HeaderType = WMIHT_NONE;
  1602. ULONG Size;
  1603. ULONG Offset;
  1604. ULONG TableIndex;
  1605. TableIndex = TotalBuffersRead % MAX_TRACE_BUFFER_CACHE_SIZE ;
  1606. pBuffer = pContext->BufferCache[TableIndex].Buffer;
  1607. if (!GetOverlappedResult(pContext->Handle, &pContext->AsynchRead, &nBytesRead, TRUE) &&
  1608. GetLastError() != ERROR_HANDLE_EOF) {
  1609. EtwpDebugPrint(("GetOverlappedResult failed with Status %d in BuildEventTable\n", GetLastError()));
  1610. break;
  1611. }
  1612. pContext->AsynchRead.Offset = (DWORD)(ReadPosition & 0xFFFFFFFF);
  1613. pContext->AsynchRead.OffsetHigh = (DWORD)(ReadPosition >> 32);
  1614. Status = EtwpSynchReadFile(pContext->Handle,
  1615. (LPVOID)pBuffer,
  1616. BufferSize,
  1617. &nBytesRead,
  1618. &pContext->AsynchRead);
  1619. if (nBytesRead == 0)
  1620. break;
  1621. ReadPosition += BufferSize;
  1622. Offset = sizeof(WMI_BUFFER_HEADER);
  1623. pEvent = &pContext->BufferList[TotalBuffersRead].Event;
  1624. HeaderType = WmiGetTraceHeader(pBuffer, Offset, &Size);
  1625. if ( (HeaderType == WMIHT_NONE) || (HeaderType == WMIHT_WNODE) || (Size == 0) ) {
  1626. TotalBuffersRead++;
  1627. continue;
  1628. }
  1629. Status = EtwpParseTraceEvent(pContext, pBuffer, Offset, HeaderType, pEvent, sizeof(EVENT_TRACE));
  1630. //
  1631. // Set up the header structure properly
  1632. //
  1633. if (Status != ERROR_SUCCESS) {
  1634. TotalBuffersRead++;
  1635. continue;
  1636. }
  1637. Offset += Size;
  1638. pContext->BufferList[TotalBuffersRead].BufferOffset = Offset;
  1639. pContext->BufferList[TotalBuffersRead].FileOffset = TotalBuffersRead;
  1640. pContext->BufferList[TotalBuffersRead].EventSize = Size;
  1641. pContext->BufferList[TotalBuffersRead].TraceType = EtwpConvertEnumToTraceType(HeaderType);
  1642. EtwpInsertBuffer(&pContext->Root, &pContext->BufferList[TotalBuffersRead]);
  1643. TotalBuffersRead++;
  1644. if (TotalBuffersRead >= pContext->BufferCount) {
  1645. break;
  1646. }
  1647. } while (1);
  1648. return ERROR_SUCCESS;
  1649. }
  1650. ULONG
  1651. EtwpProcessTraceLog(
  1652. PTRACEHANDLE HandleArray,
  1653. PEVENT_TRACE_LOGFILEW *Logfiles,
  1654. ULONG LogfileCount,
  1655. LONGLONG StartTime,
  1656. LONGLONG EndTime,
  1657. ULONG Unicode
  1658. )
  1659. /*++
  1660. Routine Description:
  1661. This routine processes an array of traces (from file or realtime input
  1662. stream). If the trace is from a file, goes through each event till the
  1663. end of file, firing event callbacks (if any) along the way. If the trace
  1664. is from realtime, it waits for event notification about buffer delivery
  1665. from the realtime callback and processes the buffer delivered in the
  1666. same way. It handles circular logfiles and windowing of data (with the
  1667. given start and end times) correctly. When more than one trace it
  1668. provides the callback in chronological order.
  1669. Arguments:
  1670. Logfiles Array of traces
  1671. LogfileCount Number of traces
  1672. StartTime Starting Time of the window of analysis
  1673. EndTime Ending Time of the window of analysis
  1674. Unicode Unicode Flag.
  1675. Returned Value:
  1676. Status Code.
  1677. --*/
  1678. {
  1679. PEVENT_TRACE_LOGFILE logfile;
  1680. ULONG Status;
  1681. PEVENT_TRACE pEvent;
  1682. PTRACELOG_CONTEXT pContext;
  1683. ULONG RealTimeDataFeed, LogFileDataFeed;
  1684. USHORT LoggerId;
  1685. TRACEHANDLE LoggerHandle = 0;
  1686. ULONG i, j;
  1687. BOOL Done = FALSE;
  1688. ACCESS_MASK DesiredAccess = TRACELOG_ACCESS_REALTIME;
  1689. LONGLONG CurrentTime = StartTime;
  1690. UCHAR SubVersion;
  1691. UCHAR SubMinorVersion;
  1692. BOOLEAN bVersionMismatch;
  1693. BOOLEAN bActiveCircular = FALSE;
  1694. PTRACE_LOGFILE_HEADER logfileHeader;
  1695. Status = EtwpCreateGuidMapping();
  1696. if (Status != ERROR_SUCCESS) {
  1697. return Status;
  1698. }
  1699. //
  1700. // After reading the First Buffer, determine the BufferSize,
  1701. // Number of Buffers written, filesize, kernel or non-kernel logger
  1702. // Set a flag to strip out the GuidMap at the end.
  1703. //
  1704. Status = EtwpProcessLogHeader( HandleArray,
  1705. Logfiles,
  1706. LogfileCount,
  1707. Unicode,
  1708. FALSE
  1709. );
  1710. if (Status != ERROR_SUCCESS) {
  1711. goto Cleanup;
  1712. }
  1713. bVersionMismatch = FALSE;
  1714. SubVersion = Logfiles[0]->LogfileHeader.VersionDetail.SubVersion;
  1715. SubMinorVersion = Logfiles[0]->LogfileHeader.VersionDetail.SubMinorVersion;
  1716. for (i=0; i < LogfileCount; i++) {
  1717. UCHAR tSV, tSMV;
  1718. logfileHeader = &Logfiles[i]->LogfileHeader;
  1719. tSV = Logfiles[i]->LogfileHeader.VersionDetail.SubVersion;
  1720. tSMV = Logfiles[i]->LogfileHeader.VersionDetail.SubMinorVersion;
  1721. if ( (SubVersion != tSV) || (SubMinorVersion != tSMV) ) {
  1722. bVersionMismatch = TRUE;
  1723. }
  1724. if ((logfileHeader->EndTime.QuadPart == 0) &&
  1725. ((logfileHeader->LogFileMode & EVENT_TRACE_FILE_MODE_CIRCULAR))) {
  1726. bActiveCircular = TRUE;
  1727. }
  1728. }
  1729. //
  1730. // Is there is a version mismatch among the files, they need to be
  1731. // processed individually.
  1732. //
  1733. if (bVersionMismatch) {
  1734. return ERROR_INVALID_PARAMETER;
  1735. }
  1736. else {
  1737. if (((SubVersion >= 1) && (SubMinorVersion >= 2)) &&
  1738. (!bActiveCircular)) {
  1739. return EtwpProcessTraceLogEx(HandleArray, Logfiles,
  1740. LogfileCount,
  1741. StartTime,
  1742. EndTime,
  1743. Unicode);
  1744. }
  1745. }
  1746. ASSERT (!bVersionMismatch);
  1747. Status = EtwpProcessGuidMaps( Logfiles, LogfileCount, Unicode );
  1748. if (Status != ERROR_SUCCESS) {
  1749. goto Cleanup;
  1750. }
  1751. //
  1752. // Set up storage
  1753. //
  1754. for (i=0; i < LogfileCount; i++) {
  1755. ULONG BufferSize, BufferCount;
  1756. ULONG SizeNeeded;
  1757. PUCHAR Space;
  1758. PTRACE_BUFFER_LIST_ENTRY Current;
  1759. pContext = (PTRACELOG_CONTEXT)Logfiles[i]->Context;
  1760. BufferSize = pContext->BufferSize;
  1761. BufferCount = pContext->BufferCount;
  1762. SizeNeeded = BufferCount * sizeof(TRACE_BUFFER_LIST_ENTRY);
  1763. pContext->BufferList = EtwpMemCommit( NULL, SizeNeeded );
  1764. if (pContext->BufferList == NULL) {
  1765. Status = ERROR_OUTOFMEMORY;
  1766. goto Cleanup;
  1767. }
  1768. RtlZeroMemory(pContext->BufferList, SizeNeeded);
  1769. //
  1770. // Allocate Buffer Cache
  1771. //
  1772. SizeNeeded = MAX_TRACE_BUFFER_CACHE_SIZE * BufferSize;
  1773. Space = EtwpMemCommit( NULL, SizeNeeded );
  1774. if (Space == NULL) {
  1775. Status = ERROR_OUTOFMEMORY;
  1776. goto Cleanup;
  1777. }
  1778. for (j=0; j<MAX_TRACE_BUFFER_CACHE_SIZE; j++) {
  1779. pContext->BufferCache[j].Index = -1;
  1780. pContext->BufferCache[j].Buffer = (PVOID)(Space + j * BufferSize);
  1781. }
  1782. pContext->BufferCacheSpace = Space;
  1783. Status = EtwpBuildEventTable(pContext);
  1784. if (Status != ERROR_SUCCESS) {
  1785. goto Cleanup;
  1786. }
  1787. Current = pContext->Root;
  1788. if (Current != NULL) {
  1789. Logfiles[i]->CurrentTime = Current->Event.Header.TimeStamp.QuadPart;
  1790. }
  1791. else {
  1792. pContext->EndOfFile = TRUE;
  1793. }
  1794. }
  1795. //
  1796. // Make the Second Pass and get the events.
  1797. //
  1798. #ifdef DBG
  1799. EtwpDumpCallbacks();
  1800. #endif
  1801. while (!Done) {
  1802. LONGLONG nextTimeStamp;
  1803. BOOL EventInRange;
  1804. //
  1805. // Check to see if end of file has been reached on all the
  1806. // files.
  1807. //
  1808. logfile = NULL;
  1809. nextTimeStamp = 0;
  1810. for (j=0; j < LogfileCount; j++) {
  1811. pContext = (PTRACELOG_CONTEXT)Logfiles[j]->Context;
  1812. if (pContext->EndOfFile)
  1813. continue;
  1814. if (nextTimeStamp == 0) {
  1815. nextTimeStamp = Logfiles[j]->CurrentTime;
  1816. logfile = Logfiles[j];
  1817. }
  1818. else if (nextTimeStamp > Logfiles[j]->CurrentTime) {
  1819. nextTimeStamp = Logfiles[j]->CurrentTime;
  1820. logfile = Logfiles[j];
  1821. }
  1822. }
  1823. if (logfile == NULL) {
  1824. break;
  1825. }
  1826. //
  1827. // if the Next event timestamp is not within the window of
  1828. // analysis, we do not fire the event callbacks.
  1829. //
  1830. EventInRange = TRUE;
  1831. // Make sure we don't deliver events that go back in time.
  1832. if ((CurrentTime != 0) && (CurrentTime > nextTimeStamp))
  1833. EventInRange = FALSE;
  1834. if ((EndTime != 0) && (EndTime < nextTimeStamp))
  1835. EventInRange = FALSE;
  1836. //
  1837. // logfile->CurrentTime can only increase. On multiproc itanium machine,
  1838. // time can go back.
  1839. //
  1840. if (CurrentTime < nextTimeStamp) {
  1841. CurrentTime = nextTimeStamp;
  1842. }
  1843. if ( (ETW_LOG_ERROR() ) && (CurrentTime > nextTimeStamp) ) {
  1844. DbgPrint("ETW: TimeStamp reversed. Prev %I64u Next %I64u\n",
  1845. CurrentTime, nextTimeStamp);
  1846. }
  1847. //
  1848. // Now advance to next event.
  1849. //
  1850. Status = EtwpAdvanceToNewEvent(logfile, EventInRange);
  1851. Done = (Status == ERROR_CANCELLED);
  1852. }
  1853. Cleanup:
  1854. for (i=0; i < LogfileCount; i++) {
  1855. pContext = (PTRACELOG_CONTEXT)Logfiles[i]->Context;
  1856. if (pContext != NULL) {
  1857. EtwpCleanupTraceLog(pContext, FALSE);
  1858. }
  1859. }
  1860. return Status;
  1861. }
  1862. ULONG
  1863. EtwpCopyLogfileInfo(
  1864. PTRACELOG_CONTEXT HandleEntry,
  1865. PEVENT_TRACE_LOGFILEW Logfile,
  1866. ULONG Unicode
  1867. )
  1868. {
  1869. ULONG bufSize;
  1870. PWCHAR ws;
  1871. //
  1872. // Allocate LogfileName and LoggerName as well
  1873. //
  1874. RtlCopyMemory(&HandleEntry->Logfile,
  1875. Logfile,
  1876. sizeof(EVENT_TRACE_LOGFILEW));
  1877. HandleEntry->Logfile.LogFileName = NULL;
  1878. HandleEntry->Logfile.LoggerName = NULL;
  1879. HandleEntry->ConversionFlags = Logfile->LogfileHeader.ReservedFlags;
  1880. if (ETW_LOG_API()) {
  1881. DbgPrint("ETW: ConversionFlags for Processing %x\n", HandleEntry->ConversionFlags);
  1882. }
  1883. if (Logfile->LogFileName != NULL) {
  1884. if (Unicode)
  1885. bufSize = (wcslen(Logfile->LogFileName) + 1) * sizeof(WCHAR);
  1886. else
  1887. bufSize = (strlen((PUCHAR)(Logfile->LogFileName)) + 1)
  1888. * sizeof(WCHAR);
  1889. ws = EtwpAlloc( bufSize );
  1890. if (ws == NULL)
  1891. return ERROR_OUTOFMEMORY;
  1892. if (Unicode) {
  1893. wcscpy(ws, Logfile->LogFileName);
  1894. }
  1895. else {
  1896. MultiByteToWideChar(CP_ACP,
  1897. 0,
  1898. (LPCSTR)Logfile->LogFileName,
  1899. -1,
  1900. (LPWSTR)ws,
  1901. bufSize / sizeof(WCHAR));
  1902. }
  1903. HandleEntry->Logfile.LogFileName = ws;
  1904. }
  1905. if (Logfile->LoggerName != NULL) {
  1906. if (Unicode)
  1907. bufSize = (wcslen(Logfile->LoggerName) + 1) * sizeof(WCHAR);
  1908. else
  1909. bufSize = (strlen((PUCHAR)(Logfile->LoggerName)) + 1)
  1910. * sizeof(WCHAR);
  1911. ws = EtwpAlloc( bufSize );
  1912. if (ws == NULL)
  1913. return ERROR_OUTOFMEMORY;
  1914. if (Unicode)
  1915. wcscpy(ws, Logfile->LoggerName);
  1916. else {
  1917. MultiByteToWideChar(CP_ACP,
  1918. 0,
  1919. (LPCSTR)Logfile->LoggerName,
  1920. -1,
  1921. (LPWSTR)ws,
  1922. bufSize / sizeof(WCHAR));
  1923. }
  1924. HandleEntry->Logfile.LoggerName = ws;
  1925. }
  1926. return ERROR_SUCCESS;
  1927. }
  1928. TRACEHANDLE
  1929. WMIAPI
  1930. OpenTraceA(
  1931. IN PEVENT_TRACE_LOGFILEA Logfile
  1932. )
  1933. /*++
  1934. Routine Description:
  1935. This is the Ansi version of the ProcessTracelogHeader routine.
  1936. Arguments:
  1937. LogFile Trace Input
  1938. Returned Value:
  1939. TraceHandle
  1940. --*/
  1941. {
  1942. ULONG status = ERROR_INVALID_PARAMETER;
  1943. PTRACELOG_CONTEXT HandleEntry = NULL;
  1944. TRACEHANDLE TraceHandle = (TRACEHANDLE)INVALID_HANDLE_VALUE;
  1945. EtwpInitProcessHeap();
  1946. if (Logfile != NULL) {
  1947. HandleEntry = EtwpAllocateTraceHandle();
  1948. if (HandleEntry == NULL) {
  1949. status = ERROR_OUTOFMEMORY;
  1950. }
  1951. else {
  1952. //
  1953. // Copy the LogFileStructure over. Converts strings to Unicode
  1954. //
  1955. TraceHandle = HandleEntry->TraceHandle;
  1956. try {
  1957. status = EtwpCopyLogfileInfo(
  1958. HandleEntry,
  1959. (PEVENT_TRACE_LOGFILEW)Logfile,
  1960. FALSE
  1961. );
  1962. //
  1963. // TODO: Once we copied the caller's memory we should use our
  1964. // private copy and also come out of the try-except block
  1965. //
  1966. if (status == ERROR_SUCCESS) {
  1967. //
  1968. // For RealTime, handle is a place holder until ProcessTrace
  1969. //
  1970. if ( (Logfile->LogFileMode & EVENT_TRACE_REAL_TIME_MODE)
  1971. != EVENT_TRACE_REAL_TIME_MODE ) {
  1972. status = EtwpCreateGuidMapping();
  1973. if (status == ERROR_SUCCESS) {
  1974. status = EtwpProcessLogHeader(
  1975. &HandleEntry->TraceHandle,
  1976. (PEVENT_TRACE_LOGFILEW*)&Logfile,
  1977. 1,
  1978. FALSE,
  1979. TRUE
  1980. );
  1981. }
  1982. }
  1983. }
  1984. }
  1985. except (EXCEPTION_EXECUTE_HANDLER) {
  1986. status = EtwpNtStatusToDosError( GetExceptionCode() );
  1987. }
  1988. }
  1989. }
  1990. if ( (status != ERROR_SUCCESS) && (HandleEntry != NULL) ) {
  1991. EtwpFreeTraceHandle(TraceHandle);
  1992. TraceHandle = (TRACEHANDLE)INVALID_HANDLE_VALUE;
  1993. }
  1994. EtwpSetDosError(status);
  1995. return TraceHandle;
  1996. }
  1997. TRACEHANDLE
  1998. WMIAPI
  1999. OpenTraceW(
  2000. IN PEVENT_TRACE_LOGFILEW Logfile
  2001. )
  2002. /*++
  2003. Routine Description:
  2004. This routine processes a trace input and returns the tracelog header.
  2005. Only for logfiles. For realtime traces, the header may not be available.
  2006. Arguments:
  2007. Logfile Trace input.
  2008. Returned Value:
  2009. Pointer to Tracelog header.
  2010. --*/
  2011. {
  2012. ULONG status = ERROR_INVALID_PARAMETER;
  2013. PTRACELOG_CONTEXT HandleEntry = NULL;
  2014. TRACEHANDLE TraceHandle = (TRACEHANDLE)INVALID_HANDLE_VALUE;
  2015. EtwpInitProcessHeap();
  2016. if (Logfile != NULL) {
  2017. HandleEntry = EtwpAllocateTraceHandle();
  2018. if (HandleEntry == NULL) {
  2019. status = ERROR_OUTOFMEMORY;
  2020. }
  2021. else {
  2022. TraceHandle = HandleEntry->TraceHandle;
  2023. try {
  2024. status = EtwpCopyLogfileInfo(
  2025. HandleEntry,
  2026. (PEVENT_TRACE_LOGFILEW)Logfile,
  2027. TRUE
  2028. );
  2029. if (status == ERROR_SUCCESS) {
  2030. if ( (Logfile->LogFileMode & EVENT_TRACE_REAL_TIME_MODE)
  2031. != EVENT_TRACE_REAL_TIME_MODE ) {
  2032. status = EtwpCreateGuidMapping();
  2033. if (status == ERROR_SUCCESS) {
  2034. status = EtwpProcessLogHeader(
  2035. &HandleEntry->TraceHandle,
  2036. (PEVENT_TRACE_LOGFILEW*)&Logfile,
  2037. 1,
  2038. TRUE,
  2039. TRUE
  2040. );
  2041. }
  2042. }
  2043. }
  2044. }
  2045. except (EXCEPTION_EXECUTE_HANDLER) {
  2046. status = EtwpNtStatusToDosError( GetExceptionCode() );
  2047. }
  2048. }
  2049. }
  2050. if ( (status != ERROR_SUCCESS) && (HandleEntry != NULL) ) {
  2051. EtwpFreeTraceHandle(TraceHandle);
  2052. TraceHandle = (TRACEHANDLE)INVALID_HANDLE_VALUE;
  2053. }
  2054. EtwpSetDosError(status);
  2055. return TraceHandle;
  2056. }
  2057. ULONG
  2058. WMIAPI
  2059. ProcessTrace(
  2060. IN PTRACEHANDLE HandleArray,
  2061. IN ULONG HandleCount,
  2062. IN LPFILETIME StartTime,
  2063. IN LPFILETIME EndTime
  2064. )
  2065. /*++
  2066. Routine Description:
  2067. This is the main ETW Consumer API. This processes one more Logfiles or
  2068. realtime streams and returns events to the caller via event callbacks.
  2069. The processing can be windowed to an interval specified by the Start
  2070. and EndTime.
  2071. Arguments:
  2072. HandleArray Array of Handles
  2073. HandleCount Count of the Handles
  2074. StartTime StartTime to window the data
  2075. EndTime EndTime to window the data
  2076. Returned Value:
  2077. Status of the operation
  2078. --*/
  2079. {
  2080. PEVENT_TRACE_LOGFILEW Logfiles[MAXLOGGERS];
  2081. PLIST_ENTRY Head, Next;
  2082. PTRACELOG_CONTEXT pHandleEntry, pEntry;
  2083. ULONG i, Status;
  2084. LONGLONG sTime, eTime;
  2085. TRACEHANDLE SavedArray[MAXLOGGERS];
  2086. PEVENT_TRACE_LOGFILE logfile;
  2087. PEVENT_TRACE pEvent;
  2088. PTRACELOG_CONTEXT pContext;
  2089. PEVENT_TRACE_PROPERTIES Properties;
  2090. ULONG szProperties;
  2091. ULONG RealTimeDataFeed = FALSE, LogFileDataFeed = FALSE;
  2092. USHORT LoggerId;
  2093. TRACEHANDLE LoggerHandle = 0;
  2094. ULONG j;
  2095. BOOL Done = FALSE;
  2096. ACCESS_MASK DesiredAccess = TRACELOG_ACCESS_REALTIME;
  2097. EtwpInitProcessHeap();
  2098. if ((HandleCount == 0) || (HandleCount >= MAXLOGGERS)) {
  2099. return ERROR_BAD_LENGTH;
  2100. }
  2101. if (HandleArray == NULL) {
  2102. return ERROR_INVALID_PARAMETER;
  2103. }
  2104. // if TraceHandleListHeadPtr is NULL,
  2105. // OpenTrace wasn't called before ProcessTrace.
  2106. if (TraceHandleListHeadPtr == NULL) {
  2107. return ERROR_INVALID_FUNCTION;
  2108. }
  2109. //
  2110. // TODO: Do we have to allocate this even for LogFile case?
  2111. //
  2112. RtlZeroMemory(Logfiles, MAXLOGGERS*sizeof(PEVENT_TRACE_LOGFILEW) );
  2113. szProperties = sizeof(EVENT_TRACE_PROPERTIES) + 2 * MAXSTR * sizeof(WCHAR);
  2114. Properties = EtwpAlloc(szProperties);
  2115. if (Properties == NULL) {
  2116. return ERROR_OUTOFMEMORY;
  2117. }
  2118. eTime = 0;
  2119. sTime = 0;
  2120. try {
  2121. if (StartTime != NULL)
  2122. sTime = *((PLONGLONG) StartTime);
  2123. if (EndTime != NULL)
  2124. eTime = *((PLONGLONG) EndTime);
  2125. if ((eTime != 0) && (eTime < sTime) ) {
  2126. Status = ERROR_INVALID_TIME;
  2127. goto Cleanup;
  2128. }
  2129. for (i=0; i<HandleCount; i++) {
  2130. SavedArray[i] = HandleArray[i];
  2131. if (SavedArray[i] == (TRACEHANDLE) INVALID_HANDLE_VALUE) {
  2132. Status = ERROR_INVALID_HANDLE;
  2133. goto Cleanup;
  2134. }
  2135. }
  2136. //
  2137. // Need to use a termination handler to free the crit sect
  2138. // properly
  2139. //
  2140. EtwpEnterPMCritSection();
  2141. for (i=0; i< HandleCount; i++) {
  2142. pHandleEntry = NULL;
  2143. Head = TraceHandleListHeadPtr;
  2144. if (Head != NULL) {
  2145. Next = Head->Flink;
  2146. while (Next != Head) {
  2147. pEntry = CONTAINING_RECORD(Next,
  2148. TRACELOG_CONTEXT,
  2149. Entry);
  2150. Next = Next->Flink;
  2151. if (SavedArray[i] == pEntry->TraceHandle) {
  2152. if (pEntry->fProcessed == FALSE) {
  2153. pHandleEntry = pEntry;
  2154. pHandleEntry->fProcessed = TRUE;
  2155. }
  2156. break;
  2157. }
  2158. }
  2159. }
  2160. if (pHandleEntry == NULL) {
  2161. Status = ERROR_INVALID_HANDLE;
  2162. EtwpLeavePMCritSection();
  2163. goto Cleanup;
  2164. }
  2165. Logfiles[i] = &pHandleEntry->Logfile;
  2166. }
  2167. EtwpLeavePMCritSection();
  2168. //
  2169. // Scan the Logfiles list and decide it's realtime or
  2170. // Logfile Proceessing.
  2171. //
  2172. for (i=0; i < HandleCount; i++) {
  2173. //
  2174. // Check to see if this is a RealTime Datafeed
  2175. //
  2176. if (Logfiles[i]->LogFileMode & EVENT_TRACE_REAL_TIME_MODE) {
  2177. if (Logfiles[i]->LoggerName == NULL) {
  2178. Status = EtwpSetDosError(ERROR_INVALID_NAME);
  2179. goto Cleanup;
  2180. }
  2181. //
  2182. // Using the LoggerName, Query the Logger to determine
  2183. // whether this is a Kernel or Usermode realtime logger.
  2184. //
  2185. RtlZeroMemory(Properties, szProperties);
  2186. Properties->Wnode.BufferSize = szProperties;
  2187. Status = EtwControlTraceW(LoggerHandle,
  2188. (LPWSTR)Logfiles[i]->LoggerName,
  2189. Properties,
  2190. EVENT_TRACE_CONTROL_QUERY);
  2191. if (Status != ERROR_SUCCESS) {
  2192. goto Cleanup;
  2193. }
  2194. if (!(Properties->LogFileMode & EVENT_TRACE_REAL_TIME_MODE)) {
  2195. Status = ERROR_WMI_INSTANCE_NOT_FOUND;
  2196. goto Cleanup;
  2197. }
  2198. Logfiles[i]->IsKernelTrace = IsEqualGUID(
  2199. &Properties->Wnode.Guid,
  2200. &SystemTraceControlGuid
  2201. );
  2202. LoggerId = WmiGetLoggerId(Properties->Wnode.HistoricalContext);
  2203. if (LoggerId == KERNEL_LOGGER_ID) {
  2204. LoggerId = 0;
  2205. }
  2206. Logfiles[i]->Filled = LoggerId; // Temporarily stash it away
  2207. Logfiles[i]->LogfileHeader.LogInstanceGuid =
  2208. Properties->Wnode.Guid;
  2209. //
  2210. // If the Logger is using UsePerfClock for TimeStamps, make
  2211. // a reference timestamp now.
  2212. //
  2213. Logfiles[i]->LogfileHeader.ReservedFlags =
  2214. Properties->Wnode.ClientContext;
  2215. //
  2216. // Save the BuffferSize for Realtime Buffer Pool Allocation
  2217. //
  2218. Logfiles[i]->BufferSize = Properties->BufferSize * 1024;
  2219. //
  2220. // This is the place to do security check on this Guid.
  2221. //
  2222. Status = EtwpCheckGuidAccess( &Properties->Wnode.Guid,
  2223. DesiredAccess );
  2224. if (Status != ERROR_SUCCESS) {
  2225. goto Cleanup;
  2226. }
  2227. RealTimeDataFeed = TRUE;
  2228. }
  2229. //
  2230. // Check to see if this is a Logfile datafeed.
  2231. //
  2232. if (!(Logfiles[i]->LogFileMode & EVENT_TRACE_REAL_TIME_MODE)) {
  2233. if (Logfiles[i]->LogFileName == NULL) {
  2234. Status = EtwpSetDosError(ERROR_BAD_PATHNAME);
  2235. goto Cleanup;
  2236. }
  2237. if ( wcslen((LPWSTR)Logfiles[i]->LogFileName) <= 0 ) {
  2238. Status = EtwpSetDosError(ERROR_BAD_PATHNAME);
  2239. goto Cleanup;
  2240. }
  2241. LogFileDataFeed = TRUE;
  2242. }
  2243. //
  2244. // We don't support both RealTimeFeed and LogFileDataFeed.
  2245. //
  2246. if (RealTimeDataFeed && LogFileDataFeed) {
  2247. Status = EtwpSetDosError(ERROR_INVALID_PARAMETER);
  2248. goto Cleanup;
  2249. }
  2250. }
  2251. if (LogFileDataFeed) {
  2252. Status = EtwpProcessTraceLog(&SavedArray[0], Logfiles,
  2253. HandleCount,
  2254. sTime,
  2255. eTime,
  2256. TRUE);
  2257. }
  2258. else {
  2259. Status = EtwpProcessRealTimeTraces(&SavedArray[0], Logfiles,
  2260. HandleCount,
  2261. sTime,
  2262. eTime,
  2263. TRUE);
  2264. }
  2265. } except (EXCEPTION_EXECUTE_HANDLER) {
  2266. Status = GetExceptionCode();
  2267. #ifdef DBG
  2268. EtwpDebugPrint(("TRACE: EtwpProcessTraceLog threw exception %X\n",
  2269. Status));
  2270. #endif
  2271. Status = EtwpSetDosError(EtwpNtStatusToDosError(Status));
  2272. }
  2273. try {
  2274. EtwpEnterPMCritSection();
  2275. for (i=0; i< HandleCount; i++) {
  2276. pHandleEntry = NULL;
  2277. Head = TraceHandleListHeadPtr;
  2278. EtwpAssert(Head);
  2279. Next = Head->Flink;
  2280. while (Next != Head) {
  2281. pEntry = CONTAINING_RECORD(Next, TRACELOG_CONTEXT, Entry);
  2282. Next = Next->Flink;
  2283. if (SavedArray[i] == pEntry->TraceHandle) {
  2284. pEntry->fProcessed = FALSE;
  2285. break;
  2286. }
  2287. }
  2288. }
  2289. EtwpLeavePMCritSection();
  2290. } except (EXCEPTION_EXECUTE_HANDLER) {
  2291. Status = GetExceptionCode();
  2292. #ifdef DBG
  2293. EtwpDebugPrint(("TRACE: EtwpProcessTraceLog threw exception %X\n",
  2294. Status));
  2295. #endif
  2296. Status = EtwpSetDosError(EtwpNtStatusToDosError(Status));
  2297. }
  2298. Cleanup:
  2299. EtwpFree(Properties);
  2300. return Status;
  2301. }
  2302. ULONG
  2303. WMIAPI
  2304. CloseTrace(
  2305. IN TRACEHANDLE TraceHandle
  2306. )
  2307. {
  2308. EtwpInitProcessHeap();
  2309. if ((TraceHandle == 0) ||
  2310. (TraceHandle == (TRACEHANDLE)INVALID_HANDLE_VALUE))
  2311. return ERROR_INVALID_HANDLE;
  2312. return EtwpFreeTraceHandle(TraceHandle);
  2313. }
  2314. VOID
  2315. EtwpGuidMapCallback(
  2316. PLIST_ENTRY GuidMapListHeadPtr,
  2317. PEVENT_TRACE pEvent
  2318. )
  2319. {
  2320. PTRACEGUIDMAP GuidMap;
  2321. EtwpInitProcessHeap();
  2322. if (pEvent == NULL)
  2323. return;
  2324. GuidMap = (PTRACEGUIDMAP) pEvent->MofData;
  2325. if (GuidMap != NULL) {
  2326. EtwpAddGuidHandleToGuidMapList(GuidMapListHeadPtr, GuidMap->GuidMapHandle, &GuidMap->Guid);
  2327. }
  2328. }
  2329. void
  2330. EtwpCleanupTraceLog(
  2331. PTRACELOG_CONTEXT pContext,
  2332. BOOLEAN bSaveLastOffset
  2333. )
  2334. {
  2335. ULONG Size;
  2336. //
  2337. // Free up the realtime context arrays and buffers
  2338. //
  2339. EtwpEnterPMCritSection();
  2340. if (pContext->IsRealTime) {
  2341. if (pContext->Root != NULL) {
  2342. EtwpFree(pContext->Root);
  2343. }
  2344. EtwpFreeRealTimeContext(pContext->RealTimeCxt);
  2345. }
  2346. else {
  2347. if (pContext->Handle != NULL) {
  2348. NtClose(pContext->Handle);
  2349. pContext->Handle = NULL;
  2350. }
  2351. }
  2352. if (pContext->BufferList != NULL) {
  2353. EtwpMemFree(pContext->BufferList);
  2354. }
  2355. if (pContext->BufferCacheSpace != NULL) {
  2356. EtwpMemFree(pContext->BufferCacheSpace);
  2357. }
  2358. EtwpCleanupGuidMapList(&pContext->GuidMapListHead);
  2359. EtwpCleanupStreamList (&pContext->StreamListHead);
  2360. if (bSaveLastOffset) {
  2361. if (ETW_LOG_API()) {
  2362. DbgPrint("ETW: Saving ReadPosition %I64u BuffersRead %d\n",
  2363. pContext->MaxReadPosition, pContext->Logfile.BuffersRead);
  2364. }
  2365. pContext->OldMaxReadPosition = pContext->MaxReadPosition;
  2366. pContext->Logfile.BuffersRead = 0;
  2367. }
  2368. //
  2369. // The following fields need to be reset since the caller
  2370. // may call ProcessTrace again with the same handle
  2371. //
  2372. Size = sizeof(TRACELOG_CONTEXT) - FIELD_OFFSET(TRACELOG_CONTEXT, fProcessed);
  2373. RtlZeroMemory(&pContext->fProcessed, Size);
  2374. InitializeListHead (&pContext->GuidMapListHead);
  2375. InitializeListHead (&pContext->StreamListHead);
  2376. EtwpLeavePMCritSection();
  2377. }
  2378. ULONG
  2379. WMIAPI
  2380. WmiGetFirstTraceOffset(
  2381. IN PWMIBUFFERINFO BufferInfo
  2382. )
  2383. /*++
  2384. Routine Description:
  2385. This is the private API for buffer walking for cluster/
  2386. debugger support.
  2387. Returns the Offset to the first event.
  2388. Arguments:
  2389. Returned Value:
  2390. Status code
  2391. --*/
  2392. {
  2393. PVOID pBuffer;
  2394. PWMI_BUFFER_HEADER pHeader;
  2395. PLONG LastByte;
  2396. if (BufferInfo == NULL) {
  2397. return 0;
  2398. }
  2399. pBuffer = BufferInfo->Buffer;
  2400. if (pBuffer == NULL) {
  2401. return 0;
  2402. }
  2403. pHeader = (PWMI_BUFFER_HEADER) pBuffer;
  2404. switch(BufferInfo->BufferSource) {
  2405. case WMIBS_CURRENT_LIST:
  2406. {
  2407. pHeader->Wnode.BufferSize = BufferInfo->BufferSize;
  2408. pHeader->ClientContext.Alignment = (UCHAR)BufferInfo->Alignment;
  2409. pHeader->Offset = pHeader->CurrentOffset;
  2410. break;
  2411. }
  2412. case WMIBS_FREE_LIST:
  2413. {
  2414. pHeader->Offset = pHeader->CurrentOffset;
  2415. if (pHeader->SavedOffset > 0)
  2416. pHeader->Offset = pHeader->SavedOffset;
  2417. if (pHeader->Offset == 0) {
  2418. pHeader->Offset = sizeof(WMI_BUFFER_HEADER);
  2419. }
  2420. pHeader->Wnode.BufferSize = BufferInfo->BufferSize;
  2421. break;
  2422. }
  2423. case WMIBS_TRANSITION_LIST:
  2424. {
  2425. if (pHeader->SavedOffset > 0) {
  2426. pHeader->Offset = pHeader->SavedOffset;
  2427. }
  2428. break;
  2429. }
  2430. case WMIBS_FLUSH_LIST:
  2431. {
  2432. if (pHeader->SavedOffset > 0) {
  2433. pHeader->Offset = pHeader->SavedOffset;
  2434. }
  2435. pHeader->Wnode.BufferSize = BufferInfo->BufferSize;
  2436. break;
  2437. }
  2438. case WMIBS_LOG_FILE:
  2439. {
  2440. break;
  2441. }
  2442. }
  2443. if (BufferInfo->BufferSource != WMIBS_LOG_FILE) {
  2444. LastByte = (PLONG) ((PUCHAR)pHeader+ pHeader->Offset);
  2445. if (pHeader->Offset <= (BufferInfo->BufferSize - sizeof(ULONG)) ) {
  2446. *LastByte = -1;
  2447. }
  2448. }
  2449. return sizeof(WMI_BUFFER_HEADER);
  2450. }
  2451. ULONG
  2452. EtwpConvertEnumToTraceType(
  2453. WMI_HEADER_TYPE eTraceType
  2454. )
  2455. {
  2456. switch(eTraceType) {
  2457. case WMIHT_SYSTEM32:
  2458. return TRACE_HEADER_TYPE_SYSTEM32;
  2459. case WMIHT_SYSTEM64:
  2460. return TRACE_HEADER_TYPE_SYSTEM64;
  2461. case WMIHT_EVENT_TRACE:
  2462. return TRACE_HEADER_TYPE_FULL_HEADER;
  2463. case WMIHT_EVENT_INSTANCE:
  2464. return TRACE_HEADER_TYPE_INSTANCE;
  2465. case WMIHT_TIMED:
  2466. return TRACE_HEADER_TYPE_TIMED;
  2467. case WMIHT_ULONG32:
  2468. return TRACE_HEADER_TYPE_ULONG32;
  2469. case WMIHT_WNODE:
  2470. return TRACE_HEADER_TYPE_WNODE_HEADER;
  2471. case WMIHT_MESSAGE:
  2472. return TRACE_HEADER_TYPE_MESSAGE;
  2473. case WMIHT_PERFINFO32:
  2474. return TRACE_HEADER_TYPE_PERFINFO32;
  2475. case WMIHT_PERFINFO64:
  2476. return TRACE_HEADER_TYPE_PERFINFO64;
  2477. default:
  2478. return 0;
  2479. }
  2480. }
  2481. WMI_HEADER_TYPE
  2482. EtwpConvertTraceTypeToEnum(
  2483. ULONG TraceType
  2484. )
  2485. {
  2486. switch(TraceType) {
  2487. case TRACE_HEADER_TYPE_SYSTEM32:
  2488. return WMIHT_SYSTEM32;
  2489. case TRACE_HEADER_TYPE_SYSTEM64:
  2490. return WMIHT_SYSTEM64;
  2491. case TRACE_HEADER_TYPE_FULL_HEADER:
  2492. return WMIHT_EVENT_TRACE;
  2493. case TRACE_HEADER_TYPE_INSTANCE:
  2494. return WMIHT_EVENT_INSTANCE;
  2495. case TRACE_HEADER_TYPE_TIMED:
  2496. return WMIHT_TIMED;
  2497. case TRACE_HEADER_TYPE_ULONG32:
  2498. return WMIHT_ULONG32;
  2499. case TRACE_HEADER_TYPE_WNODE_HEADER:
  2500. return WMIHT_WNODE;
  2501. case TRACE_HEADER_TYPE_MESSAGE:
  2502. return WMIHT_MESSAGE;
  2503. case TRACE_HEADER_TYPE_PERFINFO32:
  2504. return WMIHT_PERFINFO32;
  2505. case TRACE_HEADER_TYPE_PERFINFO64:
  2506. return WMIHT_PERFINFO64;
  2507. default:
  2508. return WMIHT_NONE;
  2509. }
  2510. }
  2511. ULONG
  2512. WMIAPI
  2513. WmiParseTraceEvent(
  2514. IN PVOID LogBuffer,
  2515. IN ULONG Offset,
  2516. IN WMI_HEADER_TYPE HeaderType,
  2517. IN OUT PVOID EventInfo,
  2518. IN ULONG EventInfoSize
  2519. )
  2520. {
  2521. return EtwpParseTraceEvent(NULL, LogBuffer, Offset, HeaderType, EventInfo, EventInfoSize);
  2522. }
  2523. PVOID
  2524. EtwpAllocTraceBuffer(
  2525. PTRACELOG_REALTIME_CONTEXT RTCxt,
  2526. ULONG BufferSize
  2527. )
  2528. {
  2529. PVOID Buffer = NULL;
  2530. PTRACE_BUFFER_HEADER Header;
  2531. PLIST_ENTRY Head, Next;
  2532. PTRACERT_BUFFER_LIST_ENTRY ListEntry;
  2533. PTRACE_BUFFER_SPACE EtwpTraceBufferSpace;
  2534. EtwpEnterPMCritSection();
  2535. EtwpTraceBufferSpace = RTCxt->EtwpTraceBufferSpace;
  2536. Head = &EtwpTraceBufferSpace->FreeListHead;
  2537. Next = Head->Flink;
  2538. while (Head != Next) {
  2539. ListEntry = CONTAINING_RECORD(Next, TRACERT_BUFFER_LIST_ENTRY, Entry);
  2540. Next = Next->Flink;
  2541. if (ListEntry->Size == BufferSize) {
  2542. goto foundList;
  2543. }
  2544. }
  2545. //
  2546. // No list for this bufferSize was found. So go Ahead and allocate one.
  2547. //
  2548. ListEntry = EtwpAlloc(sizeof(TRACERT_BUFFER_LIST_ENTRY));
  2549. if (ListEntry == NULL) {
  2550. EtwpSetDosError(ERROR_OUTOFMEMORY);
  2551. EtwpLeavePMCritSection();
  2552. return NULL;
  2553. }
  2554. RtlZeroMemory(ListEntry, sizeof(TRACERT_BUFFER_LIST_ENTRY));
  2555. ListEntry->Size = BufferSize;
  2556. InitializeListHead(&ListEntry->BufferListHead);
  2557. InsertHeadList(&EtwpTraceBufferSpace->FreeListHead, &ListEntry->Entry);
  2558. foundList:
  2559. //
  2560. // Now look for a free buffer in this list
  2561. //
  2562. Head = &ListEntry->BufferListHead;
  2563. Next = Head->Flink;
  2564. while (Head != Next) {
  2565. Header = CONTAINING_RECORD( Next, TRACE_BUFFER_HEADER, Entry );
  2566. if (((PWNODE_HEADER)Header)->BufferSize == BufferSize) {
  2567. RemoveEntryList(&Header->Entry);
  2568. Buffer = (PVOID)Header;
  2569. break;
  2570. }
  2571. Next = Next->Flink;
  2572. }
  2573. EtwpLeavePMCritSection();
  2574. //
  2575. // If No Free Buffers are found we try to allocate one and return.
  2576. //
  2577. if (Buffer == NULL) {
  2578. PVOID Space;
  2579. ULONG SizeLeft = EtwpTraceBufferSpace->Reserved -
  2580. EtwpTraceBufferSpace->Committed;
  2581. if (SizeLeft < BufferSize) {
  2582. EtwpSetDosError(ERROR_OUTOFMEMORY);
  2583. return NULL;
  2584. }
  2585. Space = (PVOID)( (PCHAR)EtwpTraceBufferSpace->Space +
  2586. EtwpTraceBufferSpace->Committed );
  2587. Buffer = EtwpMemCommit( Space, BufferSize );
  2588. if (Buffer != NULL) {
  2589. EtwpTraceBufferSpace->Committed += BufferSize;
  2590. }
  2591. }
  2592. return (Buffer);
  2593. }
  2594. VOID
  2595. EtwpFreeTraceBuffer(
  2596. PTRACELOG_REALTIME_CONTEXT RTCxt,
  2597. PVOID Buffer
  2598. )
  2599. {
  2600. PTRACE_BUFFER_HEADER Header = (PTRACE_BUFFER_HEADER)Buffer;
  2601. PLIST_ENTRY Head, Next;
  2602. ULONG BufferSize = Header->Wnode.BufferSize;
  2603. PTRACERT_BUFFER_LIST_ENTRY ListEntry;
  2604. PLIST_ENTRY BufferList = NULL;
  2605. PTRACE_BUFFER_SPACE EtwpTraceBufferSpace;
  2606. EtwpEnterPMCritSection();
  2607. EtwpTraceBufferSpace = RTCxt->EtwpTraceBufferSpace;
  2608. Head = &EtwpTraceBufferSpace->FreeListHead;
  2609. Next = Head->Flink;
  2610. while (Head != Next) {
  2611. ListEntry = CONTAINING_RECORD(Next, TRACERT_BUFFER_LIST_ENTRY, Entry);
  2612. Next = Next->Flink;
  2613. if (ListEntry->Size == BufferSize) {
  2614. BufferList = &ListEntry->BufferListHead;
  2615. break;
  2616. }
  2617. }
  2618. if (BufferList != NULL) {
  2619. InsertHeadList(BufferList, &Header->Entry);
  2620. }
  2621. else {
  2622. // We shoule not get here. If we do the buffer->Size is
  2623. // Corrupted.
  2624. EtwpAssert(BufferList == NULL);
  2625. }
  2626. EtwpLeavePMCritSection();
  2627. }
  2628. ULONG
  2629. WMIAPI
  2630. WmiOpenTraceWithCursor(
  2631. IN PWMI_MERGE_ETL_CURSOR LogCursor
  2632. )
  2633. /*++
  2634. Routine Description:
  2635. Main entry point to process Merged ETL file.
  2636. Arguments:
  2637. LogCursor pointer to WMI_MERGE_ETL_CURSOR
  2638. Returned Value:
  2639. Status
  2640. --*/
  2641. {
  2642. ULONG DosStatus = ERROR_INVALID_PARAMETER;
  2643. NTSTATUS Status;
  2644. PTRACELOG_CONTEXT HandleEntry = NULL;
  2645. TRACEHANDLE TraceHandle = (TRACEHANDLE)INVALID_HANDLE_VALUE;
  2646. PEVENT_TRACE_LOGFILEW Logfile;
  2647. PTRACELOG_CONTEXT pContext;
  2648. ULONG BufferSize;
  2649. PWMI_BUFFER_HEADER BufferHeader;
  2650. ULONG CpuNum;
  2651. BOOLEAN CpuBufferFound;
  2652. EtwpInitProcessHeap();
  2653. if (LogCursor != NULL) {
  2654. LogCursor->Base = NULL;
  2655. LogCursor->TraceMappingHandle = NULL;
  2656. LogCursor->CursorVersion = WMI_MERGE_ETL_CURSOR_VERSION;
  2657. Logfile = &LogCursor->Logfile;
  2658. HandleEntry = EtwpAllocateTraceHandle();
  2659. if (HandleEntry == NULL) {
  2660. DosStatus = ERROR_OUTOFMEMORY;
  2661. } else {
  2662. TraceHandle = HandleEntry->TraceHandle;
  2663. try {
  2664. DosStatus = EtwpCopyLogfileInfo(HandleEntry,
  2665. Logfile,
  2666. TRUE
  2667. );
  2668. if (DosStatus == ERROR_SUCCESS) {
  2669. DosStatus = EtwpCreateGuidMapping();
  2670. if (DosStatus == ERROR_SUCCESS) {
  2671. DosStatus = EtwpProcessLogHeader(&HandleEntry->TraceHandle,
  2672. &Logfile,
  2673. 1,
  2674. TRUE,
  2675. FALSE
  2676. );
  2677. }
  2678. }
  2679. } except (EXCEPTION_EXECUTE_HANDLER) {
  2680. DosStatus = EtwpNtStatusToDosError( GetExceptionCode() );
  2681. }
  2682. }
  2683. }
  2684. if (DosStatus == ERROR_SUCCESS) {
  2685. //
  2686. // Now Make sure the bit was set, indicating a MERGED ETL
  2687. //
  2688. if ((LogCursor->Logfile.LogFileMode & EVENT_TRACE_RELOG_MODE) == 0) {
  2689. //
  2690. // It is not Merged ETL.
  2691. //
  2692. DosStatus = ERROR_BAD_FORMAT;
  2693. } else {
  2694. //
  2695. // Now find out the number of CPU's, Current event, etc.
  2696. //
  2697. pContext = LogCursor->Logfile.Context;
  2698. //
  2699. // Now Create a file Mapping
  2700. //
  2701. LogCursor->TraceMappingHandle =
  2702. CreateFileMapping(pContext->Handle,
  2703. 0,
  2704. PAGE_READONLY,
  2705. 0,
  2706. 0,
  2707. NULL
  2708. );
  2709. if (LogCursor->TraceMappingHandle == NULL) {
  2710. DosStatus = GetLastError();
  2711. return DosStatus;
  2712. }
  2713. //
  2714. // MapView of the file
  2715. //
  2716. LogCursor->Base = MapViewOfFile(LogCursor->TraceMappingHandle,
  2717. FILE_MAP_READ,
  2718. 0,
  2719. 0,
  2720. 0);
  2721. if (LogCursor->Base == NULL) {
  2722. DosStatus = GetLastError();
  2723. return DosStatus;
  2724. }
  2725. //
  2726. // Now find the first event of each CPU
  2727. //
  2728. pContext = LogCursor->Logfile.Context;
  2729. BufferSize = pContext->BufferSize;
  2730. LogCursor->CurrentCpu = 0;
  2731. for (CpuNum = 0; CpuNum < LogCursor->Logfile.LogfileHeader.NumberOfProcessors; CpuNum++) {
  2732. CpuBufferFound = FALSE;
  2733. while (CpuBufferFound == FALSE) {
  2734. BufferHeader = (PWMI_BUFFER_HEADER)
  2735. ((UCHAR*) LogCursor->Base +
  2736. LogCursor->BufferCursor[CpuNum].CurrentBufferOffset.QuadPart);
  2737. if (BufferHeader->ClientContext.ProcessorNumber == CpuNum) {
  2738. CpuBufferFound = TRUE;
  2739. LogCursor->BufferCursor[CpuNum].BufferHeader = BufferHeader;
  2740. } else {
  2741. LogCursor->BufferCursor[CpuNum].CurrentBufferOffset.QuadPart += BufferSize;
  2742. if ((LogCursor->BufferCursor[CpuNum].CurrentBufferOffset.QuadPart/BufferSize) >=
  2743. LogCursor->Logfile.LogfileHeader.BuffersWritten) {
  2744. //
  2745. // Scanned the whole file;
  2746. //
  2747. LogCursor->BufferCursor[CpuNum].NoMoreEvents = TRUE;
  2748. break;
  2749. }
  2750. }
  2751. }
  2752. if (CpuBufferFound) {
  2753. //
  2754. // Found the buffer, set the offset
  2755. //
  2756. ULONG Size;
  2757. WMI_HEADER_TYPE HeaderType = WMIHT_NONE;
  2758. PVOID pBuffer;
  2759. LogCursor->BufferCursor[CpuNum].BufferHeader = BufferHeader;
  2760. LogCursor->BufferCursor[CpuNum].CurrentEventOffset = sizeof(WMI_BUFFER_HEADER);
  2761. //
  2762. // Initialize the first event in each CPU Stream.
  2763. //
  2764. pBuffer = LogCursor->BufferCursor[CpuNum].BufferHeader;
  2765. HeaderType = WmiGetTraceHeader(pBuffer,
  2766. LogCursor->BufferCursor[CpuNum].CurrentEventOffset,
  2767. &Size);
  2768. if (HeaderType != WMIHT_NONE) {
  2769. EtwpParseTraceEvent(pContext,
  2770. pBuffer,
  2771. LogCursor->BufferCursor[CpuNum].CurrentEventOffset,
  2772. HeaderType,
  2773. &LogCursor->BufferCursor[CpuNum].CurrentEvent,
  2774. sizeof(EVENT_TRACE));
  2775. LogCursor->BufferCursor[CpuNum].CurrentEventOffset += Size;
  2776. LogCursor->CurrentCpu = CpuNum;
  2777. } else {
  2778. //
  2779. // There is no event in this buffer.
  2780. //
  2781. DosStatus = ERROR_FILE_CORRUPT;
  2782. return DosStatus;
  2783. }
  2784. }
  2785. }
  2786. for (CpuNum = 0; CpuNum < LogCursor->Logfile.LogfileHeader.NumberOfProcessors; CpuNum++) {
  2787. //
  2788. // Find the first event for whole trace.
  2789. //
  2790. if (LogCursor->BufferCursor[CpuNum].NoMoreEvents == FALSE) {
  2791. if (LogCursor->BufferCursor[LogCursor->CurrentCpu].CurrentEvent.Header.TimeStamp.QuadPart >
  2792. LogCursor->BufferCursor[CpuNum].CurrentEvent.Header.TimeStamp.QuadPart) {
  2793. LogCursor->CurrentCpu = CpuNum;
  2794. }
  2795. }
  2796. }
  2797. }
  2798. } else if ( HandleEntry != NULL) {
  2799. EtwpFreeTraceHandle(TraceHandle);
  2800. TraceHandle = (TRACEHANDLE)INVALID_HANDLE_VALUE;
  2801. }
  2802. EtwpSetDosError(DosStatus);
  2803. return DosStatus;
  2804. }
  2805. ULONG
  2806. WMIAPI
  2807. WmiCloseTraceWithCursor(
  2808. IN PWMI_MERGE_ETL_CURSOR LogCursor
  2809. )
  2810. {
  2811. ULONG Status = ERROR_INVALID_PARAMETER;
  2812. if (LogCursor != NULL) {
  2813. if (LogCursor->Base != NULL) {
  2814. if (UnmapViewOfFile(LogCursor->Base) == FALSE) {
  2815. Status = GetLastError();
  2816. return Status;
  2817. } else {
  2818. Status = ERROR_SUCCESS;
  2819. }
  2820. } else {
  2821. Status = ERROR_INVALID_PARAMETER;
  2822. }
  2823. if (Status != ERROR_SUCCESS) {
  2824. return Status;
  2825. }
  2826. if (LogCursor->TraceMappingHandle != NULL) {
  2827. if (CloseHandle(LogCursor->TraceMappingHandle) == FALSE) {
  2828. Status = GetLastError();
  2829. return Status;
  2830. } else {
  2831. Status = ERROR_SUCCESS;
  2832. }
  2833. } else {
  2834. Status = ERROR_INVALID_PARAMETER;
  2835. }
  2836. }
  2837. return Status;
  2838. }
  2839. VOID
  2840. WMIAPI
  2841. WmiConvertTimestamp(
  2842. OUT PLARGE_INTEGER DestTime,
  2843. IN PLARGE_INTEGER SrcTime,
  2844. IN PWMI_MERGE_ETL_CURSOR LogCursor
  2845. )
  2846. {
  2847. EtwpCalculateCurrentTime(DestTime, SrcTime, LogCursor->Logfile.Context);
  2848. }
  2849. ULONG
  2850. WMIAPI
  2851. WmiGetNextEvent(
  2852. IN PWMI_MERGE_ETL_CURSOR LogCursor
  2853. )
  2854. {
  2855. ULONG CurrentCpu = LogCursor->CurrentCpu;
  2856. ULONG Size;
  2857. WMI_HEADER_TYPE HeaderType = WMIHT_NONE;
  2858. PVOID pBuffer;
  2859. PWMI_BUFFER_HEADER BufferHeader;
  2860. ULONG BufferSize;
  2861. PTRACELOG_CONTEXT pContext;
  2862. ULONG CpuNum;
  2863. NTSTATUS Status;
  2864. ULONG i;
  2865. BOOLEAN CpuBufferFound = FALSE;
  2866. BOOLEAN MoreEvents = FALSE;
  2867. if (LogCursor == NULL) {
  2868. return MoreEvents;
  2869. }
  2870. //
  2871. // Advance to the next event of this current CPU
  2872. //
  2873. retry:
  2874. pBuffer = LogCursor->BufferCursor[CurrentCpu].BufferHeader;
  2875. HeaderType = WmiGetTraceHeader(
  2876. pBuffer,
  2877. LogCursor->BufferCursor[CurrentCpu].CurrentEventOffset,
  2878. &Size
  2879. );
  2880. pContext = LogCursor->Logfile.Context;
  2881. if (HeaderType == WMIHT_NONE) {
  2882. //
  2883. // End of current buffer, advance to the next buffer for this CPU
  2884. //
  2885. BufferSize = pContext->BufferSize;
  2886. LogCursor->BufferCursor[CurrentCpu].CurrentBufferOffset.QuadPart
  2887. = LogCursor->BufferCursor[CurrentCpu].CurrentBufferOffset.QuadPart
  2888. + BufferSize;
  2889. if ((LogCursor->BufferCursor[CurrentCpu].CurrentBufferOffset.QuadPart /
  2890. BufferSize) >= LogCursor->Logfile.LogfileHeader.BuffersWritten) {
  2891. //
  2892. // Scanned the whole file;
  2893. //
  2894. LogCursor->BufferCursor[CurrentCpu].NoMoreEvents = TRUE;
  2895. } else {
  2896. while (CpuBufferFound == FALSE) {
  2897. BufferHeader = (PWMI_BUFFER_HEADER)
  2898. ((UCHAR*) LogCursor->Base +
  2899. LogCursor->BufferCursor[CurrentCpu].CurrentBufferOffset.QuadPart);
  2900. if (BufferHeader->ClientContext.ProcessorNumber == CurrentCpu) {
  2901. CpuBufferFound = TRUE;
  2902. } else {
  2903. LogCursor->BufferCursor[CurrentCpu].CurrentBufferOffset.QuadPart += BufferSize;
  2904. if ((LogCursor->BufferCursor[CurrentCpu].CurrentBufferOffset.QuadPart/BufferSize) >=
  2905. LogCursor->Logfile.LogfileHeader.BuffersWritten) {
  2906. //
  2907. // Scanned the whole file;
  2908. //
  2909. LogCursor->BufferCursor[CurrentCpu].NoMoreEvents = TRUE;
  2910. break;
  2911. }
  2912. }
  2913. }
  2914. }
  2915. if (CpuBufferFound) {
  2916. //
  2917. // Found the buffer, set the offset
  2918. //
  2919. LogCursor->BufferCursor[CurrentCpu].BufferHeader = BufferHeader;
  2920. LogCursor->BufferCursor[CurrentCpu].CurrentEventOffset = sizeof(WMI_BUFFER_HEADER);
  2921. goto retry;
  2922. } else {
  2923. //
  2924. // No more buffer in this CPU stream.
  2925. //
  2926. LogCursor->BufferCursor[CurrentCpu].NoMoreEvents = TRUE;
  2927. }
  2928. } else {
  2929. EtwpParseTraceEvent(pContext,
  2930. pBuffer,
  2931. LogCursor->BufferCursor[CurrentCpu].CurrentEventOffset,
  2932. HeaderType,
  2933. &LogCursor->BufferCursor[CurrentCpu].CurrentEvent,
  2934. sizeof(EVENT_TRACE));
  2935. LogCursor->BufferCursor[CurrentCpu].CurrentEventOffset += Size;
  2936. MoreEvents = TRUE;
  2937. }
  2938. //
  2939. // No more events in current CPU.
  2940. //
  2941. if (MoreEvents == FALSE) {
  2942. for (CurrentCpu=0; CurrentCpu<LogCursor->Logfile.LogfileHeader.NumberOfProcessors; CurrentCpu++) {
  2943. if (LogCursor->BufferCursor[CurrentCpu].NoMoreEvents == FALSE) {
  2944. LogCursor->CurrentCpu = CurrentCpu;
  2945. MoreEvents = TRUE;
  2946. break;
  2947. }
  2948. }
  2949. }
  2950. //
  2951. // Now find the CPU that has the next event
  2952. //
  2953. if (MoreEvents == TRUE) {
  2954. for (i=0; i<LogCursor->Logfile.LogfileHeader.NumberOfProcessors; i++) {
  2955. if (LogCursor->BufferCursor[i].NoMoreEvents == FALSE) {
  2956. if (LogCursor->BufferCursor[LogCursor->CurrentCpu].CurrentEvent.Header.TimeStamp.QuadPart >
  2957. LogCursor->BufferCursor[i].CurrentEvent.Header.TimeStamp.QuadPart) {
  2958. LogCursor->CurrentCpu = i;
  2959. }
  2960. }
  2961. }
  2962. }
  2963. //
  2964. // Finish finding the next event.
  2965. //
  2966. return MoreEvents;
  2967. }
  2968. #endif