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.

3043 lines
94 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. umlog.c
  5. Abstract:
  6. Process Private Logger.
  7. Author:
  8. 20-Oct-1998 Melur Raghuraman
  9. Revision History:
  10. --*/
  11. #include <nt.h>
  12. #include <ntrtl.h> // for ntutrl.h
  13. #include <nturtl.h> // for RTL_CRITICAL_SECTION in winbase.h/wtypes.h
  14. #include <wtypes.h> // for LPGUID in wmium.h
  15. #include "wmiump.h"
  16. #include "evntrace.h"
  17. #include "traceump.h"
  18. #include "tracelib.h"
  19. #include "trcapi.h"
  20. #include <strsafe.h>
  21. //
  22. // The following structures must match what's in ntos\wmi\tracelog.c
  23. //
  24. #define DEFAULT_BUFFER_SIZE 4096
  25. #define MAXSTR 1024
  26. #define BUFFER_STATE_UNUSED 0 // Buffer is empty, not used
  27. #define BUFFER_STATE_DIRTY 1 // Buffer is being used
  28. #define BUFFER_STATE_FULL 2 // Buffer is filled up
  29. #define BUFFER_STATE_FLUSH 4 // Buffer ready for flush
  30. #define SEMAPHORE_LIMIT 1024
  31. #define DEFAULT_AGE_LIMIT 15
  32. #define ERROR_RETRY_COUNT 10
  33. #define ROUND_TO_PAGES(Size, Page) (((ULONG)(Size) + Page-1) & ~(Page-1))
  34. #define BYTES_PER_MB 1048576 // Conversion for FileSizeLimit
  35. extern ULONG WmiTraceAlignment;
  36. extern LONG NtdllLoggerLock;
  37. extern
  38. __inline __int64 EtwpGetSystemTime();
  39. LONG EtwpLoggerCount = 0; // Use to refcount UM Log
  40. ULONG EtwpGlobalSequence = 0;
  41. RTL_CRITICAL_SECTION UMLogCritSect;
  42. #define EtwpEnterUMCritSection() RtlEnterCriticalSection(&UMLogCritSect)
  43. #define EtwpLeaveUMCritSection() RtlLeaveCriticalSection(&UMLogCritSect)
  44. #define EtwpIsLoggerOn() \
  45. ((EtwpLoggerContext != NULL) && \
  46. (EtwpLoggerContext != (PWMI_LOGGER_CONTEXT) &EtwpLoggerContext))
  47. #define EtwpIsThisLoggerOn(x) \
  48. ((x != NULL) && \
  49. (x != (PWMI_LOGGER_CONTEXT) &EtwpLoggerContext))
  50. //
  51. // Increase refcount on a logger context
  52. #define EtwpLockLogger() \
  53. InterlockedIncrement(&EtwpLoggerCount)
  54. // Decrease refcount on a logger context
  55. #define EtwpUnlockLogger() InterlockedDecrement(&EtwpLoggerCount)
  56. PWMI_LOGGER_CONTEXT EtwpLoggerContext = NULL; // Global pointer to LoggerContext
  57. LARGE_INTEGER OneSecond = {(ULONG)(-1 * 1000 * 1000 * 10), -1};
  58. // #define EtwpReleaseTraceBuffer(BufferResource) \
  59. // InterlockedDecrement(&((BufferResource)->ReferenceCount))
  60. LONG
  61. FASTCALL
  62. EtwpReleaseTraceBuffer(
  63. IN PWMI_BUFFER_HEADER BufferResource
  64. );
  65. #pragma warning( disable: 4035 ) /* Don't complain about lack of ret value */
  66. #pragma warning( disable: 4127 )
  67. #pragma warning( default: 4035 )
  68. #pragma warning( default: 4127 )
  69. #if DBG
  70. #define TraceDebug(x) DbgPrint x
  71. #else
  72. #define TraceDebug(x)
  73. #endif
  74. ULONG
  75. EtwpReceiveReply(
  76. HANDLE ReplyHandle,
  77. ULONG ReplyCount,
  78. ULONG ReplyIndex,
  79. PVOID OutBuffer,
  80. ULONG OutBufferSize
  81. );
  82. VOID
  83. EtwpLogger(
  84. IN PWMI_LOGGER_CONTEXT LoggerContext
  85. );
  86. ULONG
  87. EtwpStopUmLogger(
  88. IN ULONG WnodeSize,
  89. IN OUT ULONG *SizeUsed,
  90. OUT ULONG *SizeNeeded,
  91. IN OUT PWMI_LOGGER_INFORMATION LoggerInfo
  92. );
  93. ULONG
  94. EtwpQueryUmLogger(
  95. IN ULONG WnodeSize,
  96. IN OUT ULONG *SizeUsed,
  97. OUT ULONG *SizeNeeded,
  98. IN OUT PWMI_LOGGER_INFORMATION LoggerInfo
  99. );
  100. ULONG
  101. EtwpUpdateUmLogger(
  102. IN ULONG WnodeSize,
  103. IN OUT ULONG *SizeUsed,
  104. OUT ULONG *SizeNeeded,
  105. IN OUT PWMI_LOGGER_INFORMATION LoggerInfo
  106. );
  107. ULONG
  108. EtwpFlushUmLogger(
  109. IN ULONG WnodeSize,
  110. IN OUT ULONG *SizeUsed,
  111. OUT ULONG *SizeNeeded,
  112. IN OUT PWMI_LOGGER_INFORMATION LoggerInfo
  113. );
  114. PWMI_LOGGER_CONTEXT
  115. EtwpInitLoggerContext(
  116. IN PWMI_LOGGER_INFORMATION LoggerInfo
  117. );
  118. ULONG
  119. EtwpAllocateTraceBuffers(
  120. IN PWMI_LOGGER_CONTEXT LoggerContext
  121. );
  122. ULONG
  123. EtwpFlushBuffer(
  124. IN PWMI_LOGGER_CONTEXT LoggerContext,
  125. IN PWMI_BUFFER_HEADER Buffer,
  126. IN USHORT BufferFlag
  127. );
  128. ULONG
  129. EtwpFlushAllBuffers(
  130. IN PWMI_LOGGER_CONTEXT LoggerContext);
  131. PWMI_BUFFER_HEADER
  132. FASTCALL
  133. EtwpSwitchBuffer(
  134. IN PWMI_LOGGER_CONTEXT LoggerContext,
  135. IN PWMI_BUFFER_HEADER OldBuffer,
  136. IN ULONG Processor
  137. );
  138. ULONG
  139. EtwpFreeLoggerContext(
  140. PWMI_LOGGER_CONTEXT LoggerContext
  141. );
  142. BOOLEAN
  143. FASTCALL
  144. EtwpIsPrivateLoggerOn()
  145. {
  146. if (!EtwpIsLoggerOn())
  147. return FALSE;
  148. return ( EtwpLoggerContext->CollectionOn == TRUE);
  149. }
  150. ULONG
  151. EtwpSendUmLogRequest(
  152. IN WMITRACECODE RequestCode,
  153. IN OUT PWMI_LOGGER_INFORMATION LoggerInfo
  154. )
  155. /*++
  156. Routine Description:
  157. This routine send a UserMode Logger Request (Start/Stop/Query).
  158. Arguments:
  159. RequestCode - Request Code
  160. LoggerInfo - Logger Information necessary for the request
  161. Return Value:
  162. ERROR_SUCCESS or an error code
  163. --*/
  164. {
  165. ULONG Status;
  166. ULONG SizeNeeded;
  167. PWMICREATEUMLOGGER UmRequest;
  168. ULONG RetSize;
  169. OBJECT_ATTRIBUTES ObjectAttributes;
  170. UNICODE_STRING GuidString;
  171. WCHAR GuidObjectName[WmiGuidObjectNameLength+1];
  172. PUCHAR Buffer;
  173. PWNODE_HEADER Wnode;
  174. SizeNeeded = sizeof(WMICREATEUMLOGGER) +
  175. ((PWNODE_HEADER)LoggerInfo)->BufferSize;
  176. SizeNeeded = ALIGN_TO_POWER2 (SizeNeeded, 8);
  177. Buffer = EtwpAlloc(SizeNeeded);
  178. if (Buffer == NULL) {
  179. return ERROR_NOT_ENOUGH_MEMORY;
  180. }
  181. UmRequest = (PWMICREATEUMLOGGER) Buffer;
  182. UmRequest->ObjectAttributes = &ObjectAttributes;
  183. UmRequest->ControlGuid = LoggerInfo->Wnode.Guid;
  184. Status = EtwpBuildGuidObjectAttributes(&UmRequest->ControlGuid,
  185. &ObjectAttributes,
  186. &GuidString,
  187. GuidObjectName);
  188. if (Status == ERROR_SUCCESS) {
  189. Wnode = (PWNODE_HEADER)((PUCHAR)Buffer + sizeof(WMICREATEUMLOGGER));
  190. RtlCopyMemory(Wnode, LoggerInfo, LoggerInfo->Wnode.BufferSize);
  191. Wnode->ProviderId = RequestCode; // This Wnode is part of the Message.
  192. Status = EtwpSendWmiKMRequest(NULL,
  193. IOCTL_WMI_CREATE_UM_LOGGER,
  194. Buffer,
  195. SizeNeeded,
  196. Buffer,
  197. SizeNeeded,
  198. &RetSize,
  199. NULL);
  200. if (Status == ERROR_SUCCESS) {
  201. #if DBG
  202. TraceDebug(("ETW: Expect %d replies\n", UmRequest->ReplyCount));
  203. #endif
  204. Status = EtwpReceiveReply(UmRequest->ReplyHandle.Handle,
  205. UmRequest->ReplyCount,
  206. Wnode->Version,
  207. LoggerInfo,
  208. LoggerInfo->Wnode.BufferSize);
  209. //
  210. // This check is just a protection to make sure the handle
  211. // is valid. The handle is supposed to be valid once the
  212. // Create IOCTL succeeds.
  213. //
  214. if (Status != ERROR_INVALID_HANDLE) {
  215. NtClose(UmRequest->ReplyHandle.Handle);
  216. }
  217. }
  218. else {
  219. TraceDebug(("ETW: IOCTL_WMI_CREATE_UM_LOGGER Status %d\n", Status));
  220. }
  221. }
  222. EtwpFree(Buffer);
  223. return Status;
  224. }
  225. void
  226. EtwpAddInstanceIdToNames(
  227. PWMI_LOGGER_INFORMATION LoggerInfo,
  228. PWMI_LOGGER_CONTEXT LoggerContext
  229. )
  230. {
  231. ULONG Offset;
  232. Offset = sizeof(WMI_LOGGER_INFORMATION);
  233. LoggerInfo->LoggerName.Buffer = (PVOID)((char*)LoggerInfo + Offset);
  234. Offset += LoggerInfo->LoggerName.MaximumLength;
  235. LoggerInfo->LogFileName.Buffer = (PVOID)((char*)LoggerInfo + Offset);
  236. EtwpInitString(&LoggerContext->LoggerName, NULL, 0);
  237. RtlCreateUnicodeString(&LoggerContext->LoggerName,
  238. LoggerInfo->LoggerName.Buffer);
  239. EtwpInitString(&LoggerContext->LogFileName, NULL, 0);
  240. if (LoggerInfo->InstanceCount == 1) {
  241. RtlCreateUnicodeString(&LoggerContext->LogFileName,
  242. LoggerInfo->LogFileName.Buffer);
  243. }
  244. else {
  245. WCHAR TempStr[MAXSTR+16];
  246. LoggerInfo->InstanceId = EtwpGetCurrentProcessId();
  247. if ( LoggerInfo->LogFileName.MaximumLength <= MAXSTR) {
  248. StringCchPrintfW(TempStr, MAXSTR, L"%s_%d",
  249. LoggerInfo->LogFileName.Buffer,
  250. LoggerInfo->InstanceId);
  251. }
  252. else {
  253. StringCchCopyW(TempStr, MAXSTR, LoggerInfo->LogFileName.Buffer);
  254. }
  255. RtlCreateUnicodeString (&LoggerContext->LogFileName, TempStr);
  256. }
  257. LoggerInfo->LoggerName = LoggerContext->LoggerName;
  258. LoggerInfo->LogFileName = LoggerContext->LogFileName;
  259. }
  260. ULONG
  261. EtwpQueryUmLogger(
  262. IN ULONG WnodeSize,
  263. IN OUT ULONG *SizeUsed,
  264. OUT ULONG *SizeNeeded,
  265. IN OUT PWMI_LOGGER_INFORMATION LoggerInfo
  266. )
  267. {
  268. ULONG Offset;
  269. PWMI_LOGGER_CONTEXT LoggerContext;
  270. #if DBG
  271. LONG RefCount;
  272. RefCount =
  273. #endif
  274. EtwpLockLogger();
  275. TraceDebug(("QueryUm: %d->%d\n", RefCount-1, RefCount));
  276. LoggerContext = EtwpLoggerContext;
  277. if (!EtwpIsThisLoggerOn(LoggerContext)) {
  278. #if DBG
  279. RefCount =
  280. #endif
  281. EtwpUnlockLogger();
  282. TraceDebug(("QueryUm: %d->%d OBJECT_NOT_FOUND\n", RefCount+1,RefCount));
  283. return ERROR_OBJECT_NOT_FOUND;
  284. }
  285. *SizeUsed = 0;
  286. *SizeNeeded = sizeof(WMI_LOGGER_INFORMATION);
  287. if (WnodeSize < *SizeNeeded) {
  288. #if DBG
  289. RefCount =
  290. #endif
  291. EtwpUnlockLogger();
  292. TraceDebug(("QueryUm: %d->%d ERROR_MORE_DATA\n", RefCount+1, RefCount));
  293. return ERROR_MORE_DATA;
  294. }
  295. LoggerInfo->Wnode.Guid = LoggerContext->InstanceGuid;
  296. LoggerInfo->LogFileMode = LoggerContext->LogFileMode;
  297. LoggerInfo->MaximumFileSize = LoggerContext->MaximumFileSize;
  298. LoggerInfo->FlushTimer = (ULONG)(LoggerContext->FlushTimer.QuadPart
  299. / OneSecond.QuadPart);
  300. LoggerInfo->BufferSize = LoggerContext->BufferSize / 1024;
  301. LoggerInfo->NumberOfBuffers = LoggerContext->NumberOfBuffers;
  302. LoggerInfo->MinimumBuffers = LoggerContext->MinimumBuffers;
  303. LoggerInfo->MaximumBuffers = LoggerContext->MaximumBuffers;
  304. LoggerInfo->EventsLost = LoggerContext->EventsLost;
  305. LoggerInfo->FreeBuffers = LoggerContext->BuffersAvailable;
  306. LoggerInfo->BuffersWritten = LoggerContext->BuffersWritten;
  307. LoggerInfo->LogBuffersLost = LoggerContext->LogBuffersLost;
  308. LoggerInfo->RealTimeBuffersLost = LoggerContext->RealTimeBuffersLost;
  309. LoggerInfo->AgeLimit = (ULONG)(LoggerContext->BufferAgeLimit.QuadPart
  310. / OneSecond.QuadPart / 60);
  311. LoggerInfo->LoggerThreadId = LoggerContext->LoggerThreadId;
  312. LoggerInfo->Wnode.ClientContext = LoggerContext->UsePerfClock;
  313. WmiSetLoggerId(1,
  314. (PTRACE_ENABLE_CONTEXT) &LoggerInfo->Wnode.HistoricalContext);
  315. // Copy LogFileName and LoggerNames into Buffer, if space is available
  316. //
  317. Offset = sizeof(WMI_LOGGER_INFORMATION);
  318. if ((Offset + LoggerContext->LoggerName.MaximumLength) < WnodeSize) {
  319. LoggerInfo->LoggerName.Buffer = (PVOID)((char*)LoggerInfo + Offset);
  320. LoggerInfo->LoggerName.MaximumLength = LoggerContext->LoggerName.MaximumLength;
  321. RtlCopyUnicodeString(&LoggerInfo->LoggerName,
  322. &LoggerContext->LoggerName);
  323. *SizeNeeded += LoggerContext->LoggerName.MaximumLength;
  324. }
  325. Offset += LoggerInfo->LoggerName.MaximumLength;
  326. if ((Offset + LoggerContext->LogFileName.MaximumLength) < WnodeSize) {
  327. LoggerInfo->LogFileName.Buffer = (PVOID)((char*)LoggerInfo + Offset);
  328. LoggerInfo->LogFileName.MaximumLength = LoggerContext->LogFileName.MaximumLength;
  329. RtlCopyUnicodeString(&LoggerInfo->LogFileName,
  330. &LoggerContext->LogFileName);
  331. *SizeNeeded += LoggerContext->LogFileName.MaximumLength;
  332. }
  333. *SizeUsed = *SizeNeeded;
  334. //
  335. // Trim the return size down to essential bits.
  336. //
  337. if (*SizeNeeded < LoggerInfo->Wnode.BufferSize) {
  338. LoggerInfo->Wnode.BufferSize = *SizeNeeded;
  339. }
  340. #if DBG
  341. RefCount =
  342. #endif
  343. EtwpUnlockLogger();
  344. TraceDebug(("QueryUm: %d->%d ERROR_SUCCESS\n", RefCount+1, RefCount));
  345. return ERROR_SUCCESS;
  346. }
  347. //
  348. // For private loggers, we allow only two things to be updated:
  349. // FlushTimer and LogFileName
  350. //
  351. ULONG
  352. EtwpUpdateUmLogger(
  353. IN ULONG WnodeSize,
  354. IN OUT ULONG *SizeUsed,
  355. OUT ULONG *SizeNeeded,
  356. IN OUT PWMI_LOGGER_INFORMATION LoggerInfo
  357. )
  358. {
  359. ULONG Status = ERROR_SUCCESS;
  360. PWMI_LOGGER_CONTEXT LoggerContext;
  361. //
  362. // Check for parameters first
  363. //
  364. *SizeUsed = 0;
  365. *SizeNeeded = sizeof(WMI_LOGGER_INFORMATION);
  366. if (WnodeSize < * SizeNeeded) {
  367. return ERROR_MORE_DATA;
  368. }
  369. if (LoggerInfo->BufferSize != 0 || LoggerInfo->MinimumBuffers != 0
  370. || LoggerInfo->MaximumBuffers != 0
  371. || LoggerInfo->MaximumFileSize != 0
  372. || LoggerInfo->EnableFlags != 0
  373. || LoggerInfo->AgeLimit != 0) {
  374. return ERROR_INVALID_PARAMETER;
  375. }
  376. //
  377. // Lock logger down if it is running
  378. //
  379. EtwpLockLogger();
  380. LoggerContext = EtwpLoggerContext;
  381. if (!EtwpIsThisLoggerOn(LoggerContext) ) {
  382. EtwpUnlockLogger();
  383. return ERROR_OBJECT_NOT_FOUND;
  384. }
  385. if (((LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_CIRCULAR) &&
  386. (LoggerContext->LogFileMode & EVENT_TRACE_FILE_MODE_SEQUENTIAL))
  387. || ((LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_SEQUENTIAL)
  388. && (LoggerContext->LogFileMode & EVENT_TRACE_FILE_MODE_CIRCULAR))
  389. || (LoggerInfo->LogFileMode & EVENT_TRACE_REAL_TIME_MODE)) {
  390. EtwpUnlockLogger();
  391. return (ERROR_INVALID_PARAMETER);
  392. }
  393. LoggerInfo->LoggerName.Buffer = (PWCHAR)
  394. (((PCHAR) LoggerInfo) + sizeof(WMI_LOGGER_INFORMATION));
  395. LoggerInfo->LogFileName.Buffer = (PWCHAR)
  396. (((PCHAR) LoggerInfo) + sizeof(WMI_LOGGER_INFORMATION)
  397. + LoggerInfo->LoggerName.MaximumLength);
  398. if (LoggerInfo->FlushTimer > 0) {
  399. LoggerContext->FlushTimer.QuadPart = LoggerInfo->FlushTimer
  400. * OneSecond.QuadPart;
  401. }
  402. if (LoggerInfo->LogFileName.Length > 0) {
  403. if (LoggerContext->LogFileHandle != NULL) {
  404. PWMI_LOGGER_INFORMATION EtwpLoggerInfo = NULL;
  405. ULONG lSizeUsed;
  406. ULONG lSizeNeeded = 0;
  407. lSizeUsed = sizeof(WMI_LOGGER_INFORMATION)
  408. + 2 * MAXSTR * sizeof(WCHAR);
  409. EtwpLoggerInfo = (PWMI_LOGGER_INFORMATION) EtwpAlloc(lSizeUsed);
  410. if (EtwpLoggerInfo == NULL) {
  411. Status = ERROR_NOT_ENOUGH_MEMORY;
  412. goto Cleanup;
  413. }
  414. RtlZeroMemory(EtwpLoggerInfo, lSizeUsed);
  415. EtwpLoggerInfo->Wnode.BufferSize = lSizeUsed;
  416. EtwpLoggerInfo->Wnode.Flags |= WNODE_FLAG_TRACED_GUID;
  417. Status = EtwpQueryUmLogger(
  418. EtwpLoggerInfo->Wnode.BufferSize,
  419. & lSizeUsed,
  420. & lSizeNeeded,
  421. EtwpLoggerInfo);
  422. if (Status != ERROR_SUCCESS) {
  423. EtwpFree(EtwpLoggerInfo);
  424. goto Cleanup;
  425. }
  426. NtClose(LoggerContext->LogFileHandle);
  427. Status = EtwpFinalizeLogFileHeader(EtwpLoggerInfo);
  428. if (Status != ERROR_SUCCESS) {
  429. EtwpFree(EtwpLoggerInfo);
  430. goto Cleanup;
  431. }
  432. EtwpFree(EtwpLoggerInfo);
  433. }
  434. LoggerInfo->BufferSize = LoggerContext->BufferSize / 1024;
  435. LoggerInfo->MaximumFileSize = LoggerContext->MaximumFileSize;
  436. LoggerInfo->LogFileMode = LoggerContext->LogFileMode;
  437. if (LoggerContext->LogFileName.Buffer != NULL) {
  438. RtlFreeUnicodeString(& LoggerContext->LogFileName);
  439. }
  440. EtwpAddInstanceIdToNames(LoggerInfo, LoggerContext);
  441. Status = EtwpAddLogHeaderToLogFile(LoggerInfo, NULL, TRUE);
  442. if (Status != ERROR_SUCCESS) {
  443. goto Cleanup;
  444. }
  445. LoggerContext->LogFileHandle = LoggerInfo->LogFileHandle;
  446. RtlCreateUnicodeString(&LoggerContext->LogFileName,
  447. LoggerInfo->LogFileName.Buffer);
  448. }
  449. Cleanup:
  450. if (Status == ERROR_SUCCESS) {
  451. Status = EtwpQueryUmLogger(WnodeSize, SizeUsed, SizeNeeded, LoggerInfo);
  452. }
  453. EtwpUnlockLogger();
  454. return (Status);
  455. }
  456. ULONG
  457. EtwpFlushUmLogger(
  458. IN ULONG WnodeSize,
  459. IN OUT ULONG *SizeUsed,
  460. OUT ULONG *SizeNeeded,
  461. IN OUT PWMI_LOGGER_INFORMATION LoggerInfo
  462. )
  463. /*++
  464. Routine Description:
  465. This routine flushes active buffers. Effectively this is accomplished by
  466. putting all the buffers in the FlushList. If there is no available buffer
  467. for switching ERROR_NOT_ENOUGH_MEMORY is returned.
  468. Arguments:
  469. WnodeSize - Size of Wnode
  470. SizeUsed - Used only to pass to QueryLogger()
  471. SizeNeeded - Used only for LoggerInfo size checking.
  472. LoggerInfo - Logger Information. It will be updated.
  473. Return Value:
  474. ERROR_SUCCESS or an error code
  475. --*/
  476. {
  477. ULONG Status = ERROR_SUCCESS;
  478. PWMI_LOGGER_CONTEXT LoggerContext;
  479. PWMI_BUFFER_HEADER Buffer, OldBuffer;
  480. ULONG Offset, i;
  481. #if DBG
  482. LONG RefCount;
  483. RefCount =
  484. #endif
  485. EtwpLockLogger();
  486. LoggerContext = EtwpLoggerContext;
  487. TraceDebug(("FlushUm: %d->%d\n", RefCount-1, RefCount));
  488. if (!EtwpIsThisLoggerOn(LoggerContext) ) {
  489. #if DBG
  490. RefCount =
  491. #endif
  492. EtwpUnlockLogger();
  493. TraceDebug(("FlushUm: %d->%d OBJECT_NOT_FOUND\n", RefCount+1,RefCount));
  494. return ERROR_OBJECT_NOT_FOUND;
  495. }
  496. *SizeUsed = 0;
  497. *SizeNeeded = sizeof(WMI_LOGGER_INFORMATION);
  498. if (WnodeSize < *SizeNeeded) {
  499. #if DBG
  500. RefCount =
  501. #endif
  502. EtwpUnlockLogger();
  503. TraceDebug(("FlushUm: %d->%d ERROR_MORE_DATA\n", RefCount+1, RefCount));
  504. return ERROR_MORE_DATA;
  505. }
  506. //
  507. // Go through each buffer, mark it "FULL", and put it in the FlushList.
  508. //
  509. EtwpEnterUMCritSection();
  510. for (i = 0; i < (ULONG)LoggerContext->NumberOfProcessors; i++) {
  511. Buffer = (PWMI_BUFFER_HEADER)LoggerContext->ProcessorBuffers[i];
  512. if (Buffer == NULL)
  513. continue;
  514. if (Buffer->CurrentOffset == sizeof(WMI_BUFFER_HEADER)) {
  515. Buffer->Flags = BUFFER_STATE_UNUSED;
  516. continue;
  517. }
  518. if (Buffer->Flags == BUFFER_STATE_UNUSED) {
  519. continue;
  520. }
  521. else {
  522. Buffer->Flags = BUFFER_STATE_FULL;
  523. }
  524. // Increment the refcount so that the buffer doesn't go away
  525. InterlockedIncrement(&Buffer->ReferenceCount);
  526. Offset = Buffer->CurrentOffset;
  527. if (Offset <LoggerContext->BufferSize) {
  528. Buffer->SavedOffset = Offset; // save this for FlushBuffer
  529. }
  530. // We need a free buffer for switching. If no buffer is available, exit.
  531. if ((LoggerContext->NumberOfBuffers == LoggerContext->MaximumBuffers)
  532. && (LoggerContext->BuffersAvailable == 0)) {
  533. InterlockedDecrement(&Buffer->ReferenceCount);
  534. Status = ERROR_NOT_ENOUGH_MEMORY;
  535. TraceDebug(("FlushUm: %d->%d ERROR_NOT_ENOUGH_MEMORY\n", RefCount+1, RefCount));
  536. break;
  537. }
  538. OldBuffer = Buffer;
  539. Buffer = EtwpSwitchBuffer(LoggerContext, OldBuffer, i);
  540. if (Buffer == NULL) {
  541. // Switching failed. Exit.
  542. Buffer = OldBuffer;
  543. InterlockedDecrement(&Buffer->ReferenceCount);
  544. Status = ERROR_NOT_ENOUGH_MEMORY;
  545. TraceDebug(("FlushUm: %d->%d ERROR_NOT_ENOUGH_MEMORY\n", RefCount+1, RefCount));
  546. break;
  547. }
  548. // Decrement the refcount back.
  549. InterlockedDecrement(&OldBuffer->ReferenceCount);
  550. Buffer->ClientContext.ProcessorNumber = (UCHAR)i;
  551. // Now wake up the logger thread.
  552. NtReleaseSemaphore(LoggerContext->Semaphore, 1, NULL);
  553. }
  554. EtwpLeaveUMCritSection();
  555. if (Status == ERROR_SUCCESS) {
  556. Status = EtwpQueryUmLogger(WnodeSize, SizeUsed, SizeNeeded, LoggerInfo);
  557. }
  558. EtwpUnlockLogger();
  559. return (Status);
  560. }
  561. ULONG
  562. EtwpStartUmLogger(
  563. IN ULONG WnodeSize,
  564. IN OUT ULONG *SizeUsed,
  565. OUT ULONG *SizeNeeded,
  566. IN OUT PWMI_LOGGER_INFORMATION LoggerInfo
  567. )
  568. {
  569. NTSTATUS Status;
  570. ULONG ErrorCode;
  571. LARGE_INTEGER TimeOut = {(ULONG)(-2000 * 1000 * 10), -1}; // 2 secs
  572. UNICODE_STRING SavedLoggerName;
  573. UNICODE_STRING SavedLogFileName;
  574. PTRACE_ENABLE_CONTEXT pContext;
  575. CLIENT_ID ClientId;
  576. PWNODE_HEADER Wnode = (PWNODE_HEADER)&LoggerInfo->Wnode;
  577. PVOID RequestAddress;
  578. PVOID RequestContext;
  579. ULONG RequestCookie;
  580. ULONG BufferSize;
  581. PWMI_LOGGER_CONTEXT LoggerContext;
  582. HANDLE LoggerThreadHandle;
  583. #if DBG
  584. LONG RefCount;
  585. #endif
  586. if (LoggerInfo->Wnode.BufferSize < sizeof(WMI_LOGGER_INFORMATION))
  587. return ERROR_INVALID_PARAMETER;
  588. if ( (LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_SEQUENTIAL) &&
  589. (LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_CIRCULAR) ) {
  590. return ERROR_INVALID_PARAMETER;
  591. }
  592. if ( (LoggerInfo->LogFileMode & EVENT_TRACE_USE_GLOBAL_SEQUENCE) &&
  593. (LoggerInfo->LogFileMode & EVENT_TRACE_USE_LOCAL_SEQUENCE) ) {
  594. return ERROR_INVALID_PARAMETER;
  595. }
  596. #if DBG
  597. RefCount =
  598. #endif
  599. EtwpLockLogger();
  600. TraceDebug(("StartUm: %d->%d\n", RefCount-1, RefCount));
  601. if (InterlockedCompareExchangePointer(&EtwpLoggerContext,
  602. &EtwpLoggerContext,
  603. NULL
  604. ) != NULL) {
  605. #if DBG
  606. RefCount =
  607. #endif
  608. EtwpUnlockLogger();
  609. TraceDebug(("StartUm: %d->%d ALREADY_ENABLED\n", RefCount+1, RefCount));
  610. return ERROR_WMI_ALREADY_ENABLED;
  611. }
  612. LoggerContext = EtwpInitLoggerContext(LoggerInfo);
  613. if (LoggerContext == NULL) {
  614. #if DBG
  615. RefCount =
  616. #endif
  617. EtwpUnlockLogger();
  618. TraceDebug(("StartUm: %d->%d InitLoggerContext FAILED\n", RefCount+1, RefCount));
  619. return ERROR_NOT_ENOUGH_MEMORY;
  620. }
  621. //
  622. // Create LoggerEvent
  623. //
  624. Status = NtCreateEvent(
  625. &LoggerContext->LoggerEvent,
  626. EVENT_ALL_ACCESS,
  627. NULL,
  628. SynchronizationEvent,
  629. FALSE);
  630. if (!NT_SUCCESS(Status)) {
  631. TraceDebug(("StartUm: Error %d Creating LoggerEvent\n", ERROR_OBJECT_NOT_FOUND));
  632. // EtwpInitLoggerContext() does not do much other than allocating LoggerContext.
  633. EtwpFree(LoggerContext);
  634. return ERROR_OBJECT_NOT_FOUND;
  635. }
  636. //
  637. // The LogFileName and LoggerNames are passed in as offset to the
  638. // LOGGER_INFORMATION structure. Reassign the Pointers for UNICODE_STRING
  639. //
  640. SavedLoggerName = LoggerInfo->LoggerName;
  641. SavedLogFileName = LoggerInfo->LogFileName;
  642. //
  643. // Since there may multiple processes registering for the same control guid
  644. // we want to make sure a start logger call from all of them do not
  645. // collide on the same file. So we tag on a InstanceId to the file name.
  646. //
  647. if (LoggerInfo->LogFileMode & EVENT_TRACE_RELOG_MODE) {
  648. PSYSTEM_TRACE_HEADER RelogProp;
  649. ULONG Offset;
  650. Offset = sizeof(WMI_LOGGER_INFORMATION) +
  651. LoggerInfo->LoggerName.MaximumLength +
  652. LoggerInfo->LogFileName.MaximumLength;
  653. Offset = ALIGN_TO_POWER2 (Offset, 8);
  654. RelogProp = (PSYSTEM_TRACE_HEADER) ((PUCHAR)LoggerInfo + Offset);
  655. EtwpAddInstanceIdToNames(LoggerInfo, LoggerContext);
  656. ErrorCode = EtwpRelogHeaderToLogFile( LoggerInfo, RelogProp );
  657. }
  658. else {
  659. EtwpAddInstanceIdToNames(LoggerInfo, LoggerContext);
  660. ErrorCode = EtwpAddLogHeaderToLogFile(LoggerInfo, NULL, FALSE);
  661. }
  662. if (ErrorCode != ERROR_SUCCESS) {
  663. TraceDebug(("StartUm: LogHeadertoLogFile Error %d\n", ErrorCode));
  664. goto Cleanup;
  665. }
  666. else
  667. {
  668. ULONG Min_Buffers, Max_Buffers;
  669. ULONG NumberProcessors;
  670. NumberProcessors = LoggerInfo->NumberOfProcessors;
  671. LoggerContext->NumberOfProcessors = NumberProcessors;
  672. // EventsLost is UNIONed to NumberOfProcessors in WMI_LOGGER_INFORMATION
  673. // in UM case. Need to reset EventsLost back to 0
  674. //
  675. LoggerInfo->EventsLost = 0;
  676. Min_Buffers = NumberProcessors + 2;
  677. Max_Buffers = 1024;
  678. if (LoggerInfo->MaximumBuffers >= Min_Buffers ) {
  679. LoggerContext->MaximumBuffers = LoggerInfo->MaximumBuffers;
  680. }
  681. else {
  682. LoggerContext->MaximumBuffers = Min_Buffers + 22;
  683. }
  684. if (LoggerInfo->MinimumBuffers >= Min_Buffers &&
  685. LoggerInfo->MinimumBuffers <= LoggerContext->MaximumBuffers) {
  686. LoggerContext->MinimumBuffers = LoggerInfo->MinimumBuffers;
  687. }
  688. else {
  689. LoggerContext->MinimumBuffers = Min_Buffers;
  690. }
  691. if (LoggerContext->MaximumBuffers > Max_Buffers)
  692. LoggerContext->MaximumBuffers = Max_Buffers;
  693. if (LoggerContext->MinimumBuffers > Max_Buffers)
  694. LoggerContext->MinimumBuffers = Max_Buffers;
  695. LoggerContext->NumberOfBuffers = LoggerContext->MinimumBuffers;
  696. }
  697. LoggerContext->LogFileHandle = LoggerInfo->LogFileHandle;
  698. LoggerContext->BufferSize = LoggerInfo->BufferSize * 1024;
  699. LoggerContext->BuffersWritten = LoggerInfo->BuffersWritten;
  700. LoggerContext->ByteOffset.QuadPart = LoggerInfo->BuffersWritten
  701. * LoggerInfo->BufferSize * 1024;
  702. // For a kernel logger, FirstBufferOffset is set in the kernel.
  703. // For a private logger, we need to do it here.
  704. LoggerContext->FirstBufferOffset.QuadPart =
  705. LoggerContext->ByteOffset.QuadPart;
  706. LoggerContext->InstanceGuid = LoggerInfo->Wnode.Guid;
  707. LoggerContext->MaximumFileSize = LoggerInfo->MaximumFileSize;
  708. LoggerContext->UsePerfClock = LoggerInfo->Wnode.ClientContext;
  709. ErrorCode = EtwpAllocateTraceBuffers(LoggerContext);
  710. if (ErrorCode != ERROR_SUCCESS) {
  711. goto Cleanup;
  712. }
  713. LoggerInfo->NumberOfBuffers = LoggerContext->NumberOfBuffers;
  714. LoggerInfo->MaximumBuffers = LoggerContext->MaximumBuffers;
  715. LoggerInfo->MinimumBuffers = LoggerContext->MinimumBuffers;
  716. LoggerInfo->FreeBuffers = LoggerContext->BuffersAvailable;
  717. pContext = (PTRACE_ENABLE_CONTEXT)&LoggerInfo->Wnode.HistoricalContext;
  718. pContext->InternalFlag |= EVENT_TRACE_INTERNAL_FLAG_PRIVATE;
  719. pContext->LoggerId = 1;
  720. if (LoggerInfo->LogFileMode & EVENT_TRACE_USE_GLOBAL_SEQUENCE) {
  721. EtwpGlobalSequence = 0;
  722. LoggerContext->SequencePtr = &EtwpGlobalSequence;
  723. }
  724. else if (LoggerInfo->LogFileMode & EVENT_TRACE_USE_LOCAL_SEQUENCE)
  725. LoggerContext->SequencePtr = &LoggerContext->LocalSequence;
  726. //
  727. // We set the CollectionOn here prior to LoggerThread start in case
  728. // it takes a while for the LoggerThread to get going and we don't want
  729. // to miss any events during that time. The flood gates will be open
  730. // when we set the EtwpLoggerContext is set whether or not
  731. // logger thread started to run.
  732. //
  733. LoggerContext->CollectionOn = TRUE;
  734. LoggerThreadHandle = EtwpCreateThread(NULL,
  735. 0,
  736. (LPTHREAD_START_ROUTINE) &EtwpLogger,
  737. (LPVOID)LoggerContext,
  738. 0,
  739. (LPDWORD)&ClientId);
  740. if (LoggerThreadHandle == NULL) {
  741. ErrorCode = EtwpGetLastError();
  742. TraceDebug(("StartUm: CreateThread Failed with %d\n", ErrorCode));
  743. LoggerContext->CollectionOn = FALSE;
  744. //
  745. // Signal the LoggerEvent in case any StopTrace is blocked
  746. // waiting for LoggerThread to respond.
  747. //
  748. NtSetEvent(LoggerContext->LoggerEvent, NULL);
  749. goto Cleanup;
  750. }
  751. else {
  752. EtwpCloseHandle(LoggerThreadHandle);
  753. }
  754. //
  755. // This routine may be called from dll initialize and we can not guarantee
  756. // that the LoggerThread will be up and running to signal us. So we will
  757. // set the CollectionOn to LOGGER_ON flag and let TraceUmEvents through
  758. // upto Max Buffers. Hopefully by that time the logger thread will be
  759. // up and running. If not, we would lose events.
  760. //
  761. EtwpLoggerContext = LoggerContext;
  762. //
  763. // At this point we will start accepting TraceUmEvent calls. Also Control
  764. // operations would get through. As a result we should not touch
  765. // LoggerContext beyond this point. It may be gone.
  766. //
  767. //
  768. // Look to see if this Provider is currently enabled.
  769. //
  770. EtwpEnableDisableGuid(Wnode, WMI_ENABLE_EVENTS, TRUE);
  771. Cleanup:
  772. LoggerInfo->LogFileName = SavedLogFileName;
  773. LoggerInfo->LoggerName = SavedLoggerName;
  774. if (ErrorCode != ERROR_SUCCESS) {
  775. if (LoggerInfo->LogFileHandle) {
  776. NtClose(LoggerInfo->LogFileHandle);
  777. LoggerInfo->LogFileHandle = NULL;
  778. if (LoggerContext != NULL) {
  779. LoggerContext->LogFileHandle = NULL;
  780. }
  781. }
  782. #if DBG
  783. RefCount =
  784. #endif
  785. EtwpUnlockLogger();
  786. TraceDebug(("StartUm: %d->%d %d\n", RefCount+1, RefCount, ErrorCode));
  787. EtwpFreeLoggerContext(LoggerContext);
  788. }
  789. else {
  790. *SizeUsed = LoggerInfo->Wnode.BufferSize;
  791. *SizeNeeded = LoggerInfo->Wnode.BufferSize;
  792. // Logger remains locked with refcount = 1
  793. }
  794. return ErrorCode;
  795. }
  796. ULONG
  797. EtwpStopLoggerInstance(
  798. IN PWMI_LOGGER_CONTEXT LoggerContext
  799. )
  800. {
  801. NTSTATUS Status;
  802. LARGE_INTEGER TimeOut = {(ULONG)(-1000 * 1000 * 10), -1}; // 1sec
  803. ULONG Result;
  804. if (LoggerContext == NULL) {
  805. return ERROR_OBJECT_NOT_FOUND;
  806. }
  807. //
  808. // We can not shut down the logger if the LoggerThread never got up
  809. // to set the UMTHREAD_ON flag. Therefore, the StopUmLogger call might
  810. // fail even though IsLoggerOn calls continue to succeed.
  811. //
  812. Result = InterlockedCompareExchange(&LoggerContext->CollectionOn,
  813. FALSE,
  814. TRUE
  815. );
  816. if (!Result) {
  817. return ERROR_OBJECT_NOT_FOUND;
  818. }
  819. NtReleaseSemaphore(LoggerContext->Semaphore, 1, NULL);
  820. Status = STATUS_TIMEOUT;
  821. while (Status == STATUS_TIMEOUT) {
  822. Status = NtWaitForSingleObject(
  823. LoggerContext->LoggerEvent, FALSE, &TimeOut);
  824. #if DBG
  825. EtwpAssert(Status != STATUS_TIMEOUT);
  826. #endif
  827. }
  828. return ERROR_SUCCESS;
  829. }
  830. ULONG
  831. EtwpDisableTraceProvider(
  832. PWMI_LOGGER_INFORMATION LoggerInfo
  833. )
  834. {
  835. WNODE_HEADER Wnode;
  836. ULONG BufferSize = sizeof(WNODE_HEADER);
  837. RtlCopyMemory(&Wnode, &LoggerInfo->Wnode, BufferSize);
  838. Wnode.BufferSize = BufferSize;
  839. Wnode.ProviderId = WMI_DISABLE_EVENTS;
  840. EtwpEnableDisableGuid(&Wnode, WMI_DISABLE_EVENTS, TRUE);
  841. return ERROR_SUCCESS;
  842. }
  843. ULONG
  844. EtwpStopUmLogger(
  845. IN ULONG WnodeSize,
  846. IN OUT ULONG *SizeUsed,
  847. OUT ULONG *SizeNeeded,
  848. IN OUT PWMI_LOGGER_INFORMATION LoggerInfo
  849. )
  850. {
  851. ULONG Status = ERROR_SUCCESS;
  852. PWMI_LOGGER_CONTEXT LoggerContext;
  853. #if DBG
  854. LONG RefCount;
  855. RefCount =
  856. #endif
  857. EtwpLockLogger();
  858. LoggerContext = EtwpLoggerContext;
  859. TraceDebug(("StopUm: %d->%d\n", RefCount-1, RefCount));
  860. if (!EtwpIsThisLoggerOn(LoggerContext)) {
  861. #if DBG
  862. RefCount =
  863. #endif
  864. EtwpUnlockLogger();
  865. TraceDebug(("StopUm: %d->%d INSTANCE_NOT_FOUND\n",RefCount+1,RefCount));
  866. return (ERROR_WMI_INSTANCE_NOT_FOUND);
  867. }
  868. Status = EtwpStopLoggerInstance(LoggerContext);
  869. if (Status == ERROR_SUCCESS) {
  870. Status = EtwpQueryUmLogger(WnodeSize, SizeUsed, SizeNeeded, LoggerInfo);
  871. }
  872. if (Status != ERROR_SUCCESS) {
  873. #if DBG
  874. RefCount =
  875. #endif
  876. EtwpUnlockLogger();
  877. TraceDebug(("StopUm: %d->%d %d\n", RefCount+1, RefCount, Status));
  878. EtwpSetLastError(Status);
  879. return(Status);
  880. }
  881. //
  882. // Finalize LogHeader ?
  883. //
  884. if (Status == ERROR_SUCCESS) {
  885. LoggerInfo->BuffersWritten = LoggerContext->BuffersWritten;
  886. LoggerInfo->LogFileMode = LoggerContext->LogFileMode;
  887. LoggerInfo->EventsLost = LoggerContext->EventsLost;
  888. Status = EtwpFinalizeLogFileHeader(LoggerInfo);
  889. #if DBG
  890. if (Status != ERROR_SUCCESS) {
  891. TraceDebug(("StopUm: Error %d FinalizeLogFileHeader\n", Status));
  892. }
  893. #endif
  894. }
  895. #if DBG
  896. RefCount =
  897. #endif
  898. EtwpUnlockLogger();
  899. TraceDebug(("StopUm: %d->%d %d\n", RefCount+1, RefCount, Status));
  900. EtwpFreeLoggerContext(LoggerContext);
  901. EtwpDisableTraceProvider(LoggerInfo);
  902. return Status;
  903. }
  904. ULONG
  905. EtwpValidateLoggerInfo(
  906. PWMI_LOGGER_INFORMATION LoggerInfo
  907. )
  908. {
  909. if (LoggerInfo == NULL) {
  910. return ERROR_INVALID_DATA;
  911. }
  912. if (LoggerInfo->Wnode.BufferSize < sizeof(WMI_LOGGER_INFORMATION))
  913. return ERROR_INVALID_DATA;
  914. if (! (LoggerInfo->Wnode.Flags & WNODE_FLAG_TRACED_GUID) )
  915. return ERROR_INVALID_DATA;
  916. if (IsEqualGUID(&LoggerInfo->Wnode.Guid, &SystemTraceControlGuid)) {
  917. return ERROR_INVALID_DATA;
  918. }
  919. return ERROR_SUCCESS;
  920. }
  921. ULONG
  922. EtwpProcessUMRequest(
  923. PWMI_LOGGER_INFORMATION LoggerInfo,
  924. PVOID DeliveryContext,
  925. ULONG ReplyIndex
  926. )
  927. {
  928. ULONG Status;
  929. PWMIMBREPLY Reply;
  930. ULONG BufferSize;
  931. PUCHAR Buffer = NULL;
  932. ULONG WnodeSize = 0;
  933. ULONG SizeUsed, SizeNeeded;
  934. ULONG RequestCode = 0;
  935. ULONG RetSize;
  936. struct {
  937. WMIMBREPLY MBreply;
  938. ULONG StatusSpace;
  939. } DefaultReply;
  940. Reply = (PWMIMBREPLY) &DefaultReply;
  941. Reply->Handle.Handle = (HANDLE)DeliveryContext;
  942. Reply->ReplyIndex = ReplyIndex;
  943. BufferSize = sizeof(DefaultReply);
  944. //
  945. // If the WMI_CREATE_UM_LOGGER got blasted with random bits, we might
  946. // end up here and we need to ensure that the LoggerInfo is a valid one.
  947. //
  948. Status = EtwpValidateLoggerInfo( LoggerInfo );
  949. if (Status != ERROR_SUCCESS) {
  950. goto cleanup;
  951. }
  952. if (DeliveryContext == NULL) {
  953. Status = ERROR_INVALID_DATA;
  954. goto cleanup;
  955. }
  956. RequestCode = LoggerInfo->Wnode.ProviderId;
  957. WnodeSize = LoggerInfo->Wnode.BufferSize;
  958. SizeUsed = 0;
  959. SizeNeeded = 0;
  960. switch (RequestCode) {
  961. case WmiStartLoggerCode:
  962. Status = EtwpStartUmLogger(WnodeSize,
  963. &SizeUsed,
  964. &SizeNeeded,
  965. LoggerInfo);
  966. break;
  967. case WmiStopLoggerCode:
  968. Status = EtwpStopUmLogger(WnodeSize,
  969. &SizeUsed,
  970. &SizeNeeded,
  971. LoggerInfo);
  972. break;
  973. case WmiQueryLoggerCode:
  974. Status = EtwpQueryUmLogger(WnodeSize,
  975. &SizeUsed,
  976. &SizeNeeded,
  977. LoggerInfo);
  978. break;
  979. case WmiUpdateLoggerCode:
  980. Status = EtwpUpdateUmLogger(WnodeSize,
  981. &SizeUsed,
  982. &SizeNeeded,
  983. LoggerInfo);
  984. break;
  985. case WmiFlushLoggerCode:
  986. Status = EtwpFlushUmLogger(WnodeSize,
  987. &SizeUsed,
  988. &SizeNeeded,
  989. LoggerInfo);
  990. break;
  991. default:
  992. Status = ERROR_INVALID_PARAMETER;
  993. break;
  994. }
  995. if (Status == ERROR_SUCCESS) {
  996. BufferSize += LoggerInfo->Wnode.BufferSize;
  997. //
  998. // Does this have to be aligned to 8 bytes?
  999. //
  1000. Buffer = EtwpAlloc(BufferSize);
  1001. if (Buffer == NULL) {
  1002. Status = ERROR_NOT_ENOUGH_MEMORY;
  1003. goto cleanup;
  1004. }
  1005. else {
  1006. RtlZeroMemory(Buffer, BufferSize);
  1007. Reply = (PWMIMBREPLY) Buffer;
  1008. Reply->Handle.Handle = (HANDLE)DeliveryContext;
  1009. Reply->ReplyIndex = ReplyIndex;
  1010. if (LoggerInfo != NULL)
  1011. {
  1012. RtlCopyMemory(Reply->Message,
  1013. LoggerInfo,
  1014. LoggerInfo->Wnode.BufferSize
  1015. );
  1016. }
  1017. }
  1018. }
  1019. cleanup:
  1020. if (Status != ERROR_SUCCESS) {
  1021. BufferSize = sizeof(DefaultReply);
  1022. RtlCopyMemory(Reply->Message, &Status, sizeof(ULONG) );
  1023. }
  1024. Status = EtwpSendWmiKMRequest(NULL,
  1025. IOCTL_WMI_MB_REPLY,
  1026. Reply,
  1027. BufferSize,
  1028. Reply,
  1029. BufferSize,
  1030. &RetSize,
  1031. NULL);
  1032. if (Buffer != NULL) {
  1033. EtwpFree(Buffer);
  1034. }
  1035. return Status;
  1036. }
  1037. PWMI_LOGGER_CONTEXT
  1038. EtwpInitLoggerContext(
  1039. IN PWMI_LOGGER_INFORMATION LoggerInfo
  1040. )
  1041. {
  1042. PWMI_LOGGER_CONTEXT LoggerContext;
  1043. NTSTATUS Status;
  1044. SYSTEM_BASIC_INFORMATION SystemInfo;
  1045. LoggerContext = (PWMI_LOGGER_CONTEXT) EtwpAlloc(sizeof(WMI_LOGGER_CONTEXT));
  1046. if (LoggerContext == NULL) {
  1047. return LoggerContext;
  1048. }
  1049. RtlZeroMemory(LoggerContext, sizeof(WMI_LOGGER_CONTEXT));
  1050. if (LoggerInfo->BufferSize > 0) {
  1051. LoggerContext->BufferSize = LoggerInfo->BufferSize * 1024;
  1052. }
  1053. else {
  1054. LoggerContext->BufferSize = DEFAULT_BUFFER_SIZE;
  1055. }
  1056. LoggerInfo->BufferSize = LoggerContext->BufferSize / 1024;
  1057. Status = NtQuerySystemInformation( SystemBasicInformation,
  1058. &SystemInfo,
  1059. sizeof (SystemInfo),
  1060. NULL);
  1061. if (!NT_SUCCESS(Status)) {
  1062. EtwpFree(LoggerContext);
  1063. return NULL;
  1064. }
  1065. //
  1066. // Round the Buffer Size to page size multiple and save it
  1067. // for allocation later.
  1068. //
  1069. LoggerContext->BufferPageSize = ROUND_TO_PAGES(LoggerContext->BufferSize,
  1070. SystemInfo.PageSize);
  1071. LoggerContext->LogFileHandle = LoggerInfo->LogFileHandle;
  1072. LoggerContext->ByteOffset.QuadPart = LoggerInfo->BuffersWritten
  1073. * LoggerInfo->BufferSize * 1024;
  1074. LoggerContext->LogFileMode = EVENT_TRACE_PRIVATE_LOGGER_MODE;
  1075. if (LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_CIRCULAR)
  1076. LoggerContext->LogFileMode |= EVENT_TRACE_FILE_MODE_CIRCULAR;
  1077. else
  1078. LoggerContext->LogFileMode |= EVENT_TRACE_FILE_MODE_SEQUENTIAL;
  1079. if (LoggerInfo->LogFileMode & EVENT_TRACE_RELOG_MODE) {
  1080. LoggerContext->LogFileMode |= EVENT_TRACE_RELOG_MODE;
  1081. }
  1082. LoggerContext->EventsLost = 0;
  1083. LoggerContext->BuffersWritten = LoggerInfo->BuffersWritten;
  1084. LoggerContext->BuffersAvailable = LoggerContext->NumberOfBuffers;
  1085. LoggerContext->ProcessorBuffers = NULL;
  1086. LoggerContext->StartTime.QuadPart = EtwpGetSystemTime();
  1087. InitializeListHead(&LoggerContext->FreeList);
  1088. InitializeListHead(&LoggerContext->FlushList);
  1089. LoggerContext->BufferAgeLimit.QuadPart =
  1090. 15 * OneSecond.QuadPart * 60 * DEFAULT_AGE_LIMIT;
  1091. if (LoggerInfo->AgeLimit > 0) {
  1092. LoggerContext->BufferAgeLimit.QuadPart =
  1093. LoggerInfo->AgeLimit * OneSecond.QuadPart * 60;
  1094. }
  1095. else if (LoggerInfo->AgeLimit < 0)
  1096. LoggerContext->BufferAgeLimit.QuadPart = 0;
  1097. Status = NtCreateSemaphore(
  1098. &LoggerContext->Semaphore,
  1099. SEMAPHORE_ALL_ACCESS,
  1100. NULL,
  1101. 0,
  1102. SEMAPHORE_LIMIT);
  1103. if (!NT_SUCCESS(Status)) {
  1104. EtwpFree(LoggerContext);
  1105. return NULL;
  1106. }
  1107. return LoggerContext;
  1108. }
  1109. PWMI_BUFFER_HEADER
  1110. FASTCALL
  1111. EtwpGetFreeBuffer(
  1112. IN PWMI_LOGGER_CONTEXT LoggerContext
  1113. )
  1114. {
  1115. PWMI_BUFFER_HEADER Buffer = NULL;
  1116. //
  1117. // Note: This routine must be called with UMCritSect Held
  1118. //
  1119. if (IsListEmpty(&LoggerContext->FreeList)) {
  1120. ULONG BufferSize = LoggerContext->BufferPageSize;
  1121. ULONG MaxBuffers = LoggerContext->MaximumBuffers;
  1122. ULONG NumberOfBuffers = LoggerContext->NumberOfBuffers;
  1123. if (NumberOfBuffers < MaxBuffers) {
  1124. Buffer = (PWMI_BUFFER_HEADER)
  1125. EtwpMemCommit(
  1126. (PVOID)((char*)LoggerContext->BufferSpace +
  1127. BufferSize * NumberOfBuffers),
  1128. BufferSize);
  1129. if (Buffer != NULL) {
  1130. RtlZeroMemory(Buffer, sizeof(WMI_BUFFER_HEADER));
  1131. Buffer->CurrentOffset = sizeof(WMI_BUFFER_HEADER);
  1132. Buffer->Flags = BUFFER_STATE_DIRTY;
  1133. Buffer->ReferenceCount = 0;
  1134. Buffer->SavedOffset = 0;
  1135. Buffer->Wnode.ClientContext = 0;
  1136. InterlockedIncrement(&LoggerContext->NumberOfBuffers);
  1137. }
  1138. }
  1139. }
  1140. else {
  1141. PLIST_ENTRY pEntry = RemoveHeadList(&LoggerContext->FreeList);
  1142. if (pEntry != NULL) {
  1143. Buffer = CONTAINING_RECORD(pEntry, WMI_BUFFER_HEADER, Entry);
  1144. InterlockedDecrement(&LoggerContext->BuffersAvailable);
  1145. Buffer->CurrentOffset = sizeof(WMI_BUFFER_HEADER);
  1146. Buffer->Flags = BUFFER_STATE_DIRTY;
  1147. Buffer->SavedOffset = 0;
  1148. Buffer->ReferenceCount = 0;
  1149. Buffer->Wnode.ClientContext = 0;
  1150. }
  1151. }
  1152. return Buffer;
  1153. }
  1154. ULONG
  1155. EtwpAllocateTraceBuffers(
  1156. IN PWMI_LOGGER_CONTEXT LoggerContext
  1157. )
  1158. /*++
  1159. Routine Description:
  1160. This routine is called to allocate the necessary buffers for user-mode
  1161. only logging. Need to have the UMCritSection to touch the lists.
  1162. Arguments:
  1163. None
  1164. Return Value:
  1165. Status of allocating the buffers
  1166. --*/
  1167. {
  1168. ULONG Processors;
  1169. ULONG BufferSize;
  1170. ULONG BufferPageSize;
  1171. ULONG NumberOfBuffers;
  1172. ULONG i;
  1173. PVOID BufferSpace;
  1174. PWMI_BUFFER_HEADER Buffer;
  1175. Processors = LoggerContext->NumberOfProcessors;
  1176. if (Processors == 0)
  1177. Processors = 1;
  1178. BufferSize = LoggerContext->BufferSize;
  1179. if (BufferSize < 1024)
  1180. BufferSize = 4096;
  1181. NumberOfBuffers = LoggerContext->NumberOfBuffers;
  1182. if (NumberOfBuffers < Processors+1)
  1183. NumberOfBuffers = Processors + 1;
  1184. //
  1185. // Determine the number of processors first
  1186. //
  1187. LoggerContext->ProcessorBuffers = EtwpAlloc( Processors
  1188. * sizeof(PWMI_BUFFER_HEADER));
  1189. if (LoggerContext->ProcessorBuffers == NULL) {
  1190. return ERROR_NOT_ENOUGH_MEMORY;
  1191. }
  1192. BufferSpace = EtwpMemReserve( LoggerContext->MaximumBuffers *
  1193. LoggerContext->BufferPageSize );
  1194. if (BufferSpace == NULL) {
  1195. EtwpFree(LoggerContext->ProcessorBuffers);
  1196. LoggerContext->ProcessorBuffers = NULL;
  1197. return ERROR_NOT_ENOUGH_MEMORY;
  1198. }
  1199. LoggerContext->BufferSpace = BufferSpace;
  1200. for (i=0; i<NumberOfBuffers; i++) {
  1201. Buffer = (PWMI_BUFFER_HEADER)
  1202. EtwpMemCommit(
  1203. (PVOID)((char*)BufferSpace + i * LoggerContext->BufferPageSize),
  1204. BufferSize);
  1205. if (Buffer == NULL) {
  1206. EtwpMemFree(LoggerContext->BufferSpace);
  1207. EtwpFree(LoggerContext->ProcessorBuffers);
  1208. LoggerContext->ProcessorBuffers = NULL;
  1209. LoggerContext->BufferSpace = NULL;
  1210. return ERROR_NOT_ENOUGH_MEMORY;
  1211. }
  1212. RtlZeroMemory(Buffer, sizeof(WMI_BUFFER_HEADER));
  1213. Buffer->TimeStamp.QuadPart = EtwpGetSystemTime();
  1214. Buffer->CurrentOffset = sizeof(WMI_BUFFER_HEADER);
  1215. Buffer->Wnode.Flags = BUFFER_STATE_DIRTY;
  1216. InsertTailList(&LoggerContext->FreeList, & (Buffer->Entry));
  1217. }
  1218. LoggerContext->NumberOfBuffers = NumberOfBuffers;
  1219. LoggerContext->BuffersAvailable = NumberOfBuffers;
  1220. for (i=0; i<Processors; i++) {
  1221. Buffer = (PWMI_BUFFER_HEADER) EtwpGetFreeBuffer(LoggerContext);
  1222. LoggerContext->ProcessorBuffers[i] = Buffer;
  1223. if (Buffer != NULL) {
  1224. Buffer->ClientContext.ProcessorNumber = (UCHAR) i;
  1225. }
  1226. else {
  1227. EtwpMemFree(LoggerContext->BufferSpace);
  1228. EtwpFree(LoggerContext->ProcessorBuffers);
  1229. LoggerContext->ProcessorBuffers = NULL;
  1230. LoggerContext->BufferSpace = NULL;
  1231. return ERROR_NOT_ENOUGH_MEMORY;
  1232. }
  1233. }
  1234. return ERROR_SUCCESS;
  1235. }
  1236. VOID
  1237. EtwpLogger(
  1238. IN PWMI_LOGGER_CONTEXT LoggerContext
  1239. )
  1240. /*++
  1241. Routine Description:
  1242. This function is the logger itself. It is started as a separate thread.
  1243. It will not return until someone has stopped data collection or it
  1244. is not successful is flushing out a buffer (e.g. disk is full).
  1245. Arguments:
  1246. None.
  1247. Return Value:
  1248. The status of running the buffer manager
  1249. --*/
  1250. {
  1251. NTSTATUS Status=STATUS_SUCCESS;
  1252. ULONG ErrorCount=0;
  1253. PCLIENT_ID Cid;
  1254. LoggerContext->LoggerStatus = Status;
  1255. //
  1256. // Elevate the priority of the Logging thread to highest
  1257. //
  1258. if (!EtwpSetThreadPriority(NtCurrentThread(), THREAD_PRIORITY_HIGHEST)) {
  1259. TraceDebug(("ETW: SetLoggerThreadPriority Failed with %d\n", EtwpGetLastError()));
  1260. }
  1261. Cid = &NtCurrentTeb()->ClientId;
  1262. LoggerContext->LoggerThreadId = Cid->UniqueThread;
  1263. InterlockedDecrement(&NtdllLoggerLock);
  1264. // by now, the caller has been notified that the logger is running
  1265. //
  1266. // Loop and wait for buffers to be filled until someone turns off CollectionOn
  1267. //
  1268. while (LoggerContext->CollectionOn) {
  1269. ULONG Counter;
  1270. ULONG DelayFlush;
  1271. PLARGE_INTEGER FlushTimer;
  1272. PWMI_BUFFER_HEADER Buffer;
  1273. PLIST_ENTRY pEntry;
  1274. LIST_ENTRY FlushList;
  1275. BOOLEAN StopLogging = FALSE;
  1276. ULONG i;
  1277. if (LoggerContext->FlushTimer.QuadPart == 0) {
  1278. FlushTimer = NULL;
  1279. }
  1280. else {
  1281. FlushTimer = &LoggerContext->FlushTimer;
  1282. }
  1283. Status = NtWaitForSingleObject( LoggerContext->Semaphore, FALSE,
  1284. FlushTimer);
  1285. DelayFlush = FALSE;
  1286. if ( Status == WAIT_TIMEOUT) {
  1287. //
  1288. // FlushTimer used, and we just timed out. Go through per processor buffer
  1289. // and mark each as FULL so that it will get flushed next time
  1290. //
  1291. for (i=0; i<(ULONG)LoggerContext->NumberOfProcessors; i++) {
  1292. Buffer = (PWMI_BUFFER_HEADER)LoggerContext->ProcessorBuffers[i];
  1293. if (Buffer == NULL)
  1294. continue;
  1295. if (Buffer->CurrentOffset == sizeof(WMI_BUFFER_HEADER))
  1296. Buffer->Flags = BUFFER_STATE_UNUSED;
  1297. if (Buffer->Flags != BUFFER_STATE_UNUSED) {
  1298. Buffer->Flags = BUFFER_STATE_FULL;
  1299. DelayFlush = TRUE; // let ReserveTraceBuffer send semaphore
  1300. }
  1301. }
  1302. }
  1303. if (DelayFlush) // will only be TRUE if FlushTimer is used
  1304. continue;
  1305. if (IsListEmpty(&LoggerContext->FlushList)){ //shouldn't happen normally
  1306. continue;
  1307. }
  1308. EtwpEnterUMCritSection();
  1309. //
  1310. // Copy the current LoggerContext->Flushlist information to
  1311. // new FlushList
  1312. //
  1313. FlushList.Flink = LoggerContext->FlushList.Flink;
  1314. FlushList.Flink->Blink = &FlushList;
  1315. FlushList.Blink = LoggerContext->FlushList.Blink;
  1316. FlushList.Blink->Flink = &FlushList;
  1317. //
  1318. // Reinitialize LoggerContext->FlushList
  1319. //
  1320. InitializeListHead(&LoggerContext->FlushList);
  1321. EtwpLeaveUMCritSection();
  1322. do{
  1323. pEntry = IsListEmpty(&FlushList) ? NULL
  1324. : RemoveHeadList(&FlushList);
  1325. if (pEntry ){
  1326. Buffer = CONTAINING_RECORD(pEntry, WMI_BUFFER_HEADER, Entry);
  1327. #if DBG
  1328. EtwpAssert(Buffer->Flags != BUFFER_STATE_UNUSED);
  1329. #endif
  1330. // If the refcount is not 0, someone is still writing to it.
  1331. // Put it back in the regular flushlist.
  1332. if (Buffer->ReferenceCount != 0) {
  1333. EtwpEnterUMCritSection();
  1334. InsertHeadList(&LoggerContext->FlushList, &Buffer->Entry);
  1335. EtwpLeaveUMCritSection();
  1336. continue;
  1337. }
  1338. Status = EtwpFlushBuffer(LoggerContext, Buffer, WMI_BUFFER_FLAG_NORMAL);
  1339. EtwpEnterUMCritSection();
  1340. if (LoggerContext->BufferAgeLimit.QuadPart == 0) {
  1341. InsertTailList(&LoggerContext->FreeList, &Buffer->Entry);
  1342. }
  1343. else {
  1344. InsertHeadList(&LoggerContext->FreeList, &Buffer->Entry);
  1345. }
  1346. EtwpLeaveUMCritSection();
  1347. if (!NT_SUCCESS(Status)) {
  1348. if((Status == STATUS_LOG_FILE_FULL) ||
  1349. (Status == STATUS_NO_DATA_DETECTED) ||
  1350. (Status == STATUS_SEVERITY_WARNING)){
  1351. if (Status == STATUS_LOG_FILE_FULL){
  1352. ErrorCount++;
  1353. } else {
  1354. ErrorCount = 0; // reset to zero otherwise
  1355. }
  1356. if (ErrorCount > ERROR_RETRY_COUNT){
  1357. StopLogging = TRUE;
  1358. break;
  1359. }
  1360. } else {
  1361. StopLogging = TRUE; // Some Kind of Severe Error
  1362. break;
  1363. }
  1364. }
  1365. }
  1366. }while( pEntry );
  1367. if (StopLogging) {
  1368. #if DBG
  1369. LONG RefCount;
  1370. #endif
  1371. Status = NtClose(LoggerContext->LogFileHandle);
  1372. LoggerContext->LogFileHandle = NULL;
  1373. // Need to set event since EtwpStopLoggerInstance
  1374. // will wait for it to be set.
  1375. NtSetEvent(LoggerContext->LoggerEvent, NULL);
  1376. EtwpStopLoggerInstance(LoggerContext);
  1377. // Need to Deref once to set the RefCount to 0
  1378. // before calling EtwpFreeLoggerContext.
  1379. #if DBG
  1380. RefCount =
  1381. #endif
  1382. EtwpUnlockLogger();
  1383. TraceDebug(("EtwpLogger: %d->%d\n", RefCount-1, RefCount));
  1384. EtwpFreeLoggerContext (LoggerContext);
  1385. EtwpSetDosError(EtwpNtStatusToDosError(Status));
  1386. EtwpExitThread(0);
  1387. }
  1388. } // while loop
  1389. // if a normal collection end, flush out all the buffers before stopping
  1390. //
  1391. EtwpFlushAllBuffers(LoggerContext);
  1392. NtSetEvent(LoggerContext->LoggerEvent, NULL);
  1393. EtwpExitThread(0); // check to see if this thread terminate itself with this
  1394. }
  1395. ULONG
  1396. EtwpFlushBuffer(
  1397. IN PWMI_LOGGER_CONTEXT LoggerContext,
  1398. IN PWMI_BUFFER_HEADER Buffer,
  1399. IN USHORT BufferFlag
  1400. )
  1401. /*++
  1402. Routine Description:
  1403. This function is responsible for flushing a filled buffer out to
  1404. disk. Assumes a FileHandle is available to write to.
  1405. Arguments:
  1406. LoggerContext Context of the logger
  1407. Buffer Buffer to flush
  1408. BufferFlag Flag
  1409. Return Value:
  1410. The status of flushing the buffer
  1411. --*/
  1412. {
  1413. IO_STATUS_BLOCK IoStatus;
  1414. NTSTATUS Status = STATUS_SUCCESS;
  1415. PWMI_BUFFER_HEADER OldBuffer;
  1416. ULONG BufferSize;
  1417. //
  1418. // Grab the buffer to be flushed
  1419. //
  1420. BufferSize = LoggerContext->BufferSize;
  1421. //
  1422. // Put end of record marker in buffer if available space
  1423. //
  1424. if (Buffer->SavedOffset > 0) {
  1425. Buffer->Offset = Buffer->SavedOffset;
  1426. }
  1427. else {
  1428. Buffer->Offset = Buffer->CurrentOffset;
  1429. }
  1430. if (Buffer->Offset < BufferSize) {
  1431. RtlFillMemory(
  1432. (char *) Buffer + Buffer->Offset,
  1433. BufferSize - Buffer->Offset,
  1434. 0xFF);
  1435. }
  1436. if (Buffer->Offset < sizeof(WMI_BUFFER_HEADER)) { // should not happen
  1437. Status = STATUS_INVALID_PARAMETER;
  1438. goto ResetTraceBuffer;
  1439. }
  1440. //
  1441. // If the Buffer type is FlushMarker, then we write it even if it's
  1442. // empty
  1443. //
  1444. if ( (Buffer->Offset == sizeof(WMI_BUFFER_HEADER)) &&
  1445. (BufferFlag != WMI_BUFFER_FLAG_FLUSH_MARKER) ) { // empty buffer
  1446. Status = STATUS_NO_DATA_DETECTED;
  1447. goto ResetTraceBuffer;
  1448. }
  1449. Buffer->BufferFlag = BufferFlag;
  1450. Status = STATUS_SUCCESS;
  1451. Buffer->Wnode.BufferSize = BufferSize;
  1452. Buffer->ClientContext.LoggerId = (USHORT) LoggerContext->LoggerId;
  1453. Buffer->ClientContext.Alignment = (UCHAR) WmiTraceAlignment;
  1454. RtlCopyMemory(&Buffer->Wnode.Guid,
  1455. &LoggerContext->InstanceGuid,
  1456. sizeof(GUID));
  1457. Buffer->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
  1458. Buffer->Wnode.TimeStamp.QuadPart = EtwpGetSystemTime();
  1459. if (LoggerContext->LogFileHandle == NULL) {
  1460. goto ResetTraceBuffer;
  1461. }
  1462. if (LoggerContext->MaximumFileSize > 0) { // if quota given
  1463. ULONG64 FileSize = LoggerContext->LastFlushedBuffer * BufferSize;
  1464. ULONG64 FileLimit = LoggerContext->MaximumFileSize * BYTES_PER_MB;
  1465. if (LoggerContext->LogFileMode & EVENT_TRACE_USE_KBYTES_FOR_SIZE) {
  1466. FileLimit = LoggerContext->MaximumFileSize * 1024;
  1467. }
  1468. if ( FileSize >= FileLimit ) { // reaches maximum file size
  1469. ULONG LoggerMode = LoggerContext->LogFileMode & 0X000000FF;
  1470. LoggerMode &= ~EVENT_TRACE_FILE_MODE_APPEND;
  1471. LoggerMode &= ~EVENT_TRACE_FILE_MODE_PREALLOCATE;
  1472. switch (LoggerMode) {
  1473. case EVENT_TRACE_FILE_MODE_SEQUENTIAL :
  1474. // do not write to logfile anymore
  1475. Status = STATUS_LOG_FILE_FULL; // control needs to stop logging
  1476. // need to fire up a Wmi Event to control console
  1477. break;
  1478. case EVENT_TRACE_FILE_MODE_CIRCULAR :
  1479. {
  1480. // reposition file
  1481. LoggerContext->ByteOffset
  1482. = LoggerContext->FirstBufferOffset;
  1483. LoggerContext->LastFlushedBuffer = (ULONG)
  1484. (LoggerContext->FirstBufferOffset.QuadPart
  1485. / LoggerContext->BufferSize);
  1486. break;
  1487. }
  1488. default :
  1489. break;
  1490. }
  1491. }
  1492. }
  1493. if (NT_SUCCESS(Status)) {
  1494. Status = NtWriteFile(
  1495. LoggerContext->LogFileHandle,
  1496. NULL,
  1497. NULL,
  1498. NULL,
  1499. &IoStatus,
  1500. Buffer,
  1501. BufferSize,
  1502. &LoggerContext->ByteOffset,
  1503. NULL);
  1504. }
  1505. if (NT_SUCCESS(Status)) {
  1506. LoggerContext->ByteOffset.QuadPart += BufferSize;
  1507. }
  1508. ResetTraceBuffer:
  1509. if (NT_SUCCESS(Status)) {
  1510. LoggerContext->BuffersWritten++;
  1511. LoggerContext->LastFlushedBuffer++;
  1512. }
  1513. else {
  1514. if ((Status != STATUS_NO_DATA_DETECTED) &&
  1515. (Status != STATUS_SEVERITY_WARNING))
  1516. LoggerContext->LogBuffersLost++;
  1517. }
  1518. //
  1519. // Reset the buffer state
  1520. //
  1521. Buffer->BufferType = WMI_BUFFER_TYPE_GENERIC;
  1522. Buffer->SavedOffset = 0;
  1523. Buffer->ReferenceCount = 0;
  1524. Buffer->Flags = BUFFER_STATE_UNUSED;
  1525. //
  1526. // Try and remove an unused buffer if it has not been used for a while
  1527. //
  1528. InterlockedIncrement(& LoggerContext->BuffersAvailable);
  1529. return Status;
  1530. }
  1531. PVOID
  1532. FASTCALL
  1533. EtwpReserveTraceBuffer(
  1534. IN ULONG RequiredSize,
  1535. OUT PWMI_BUFFER_HEADER *BufferResource
  1536. )
  1537. {
  1538. PWMI_BUFFER_HEADER Buffer, OldBuffer;
  1539. PVOID ReservedSpace;
  1540. ULONG Offset;
  1541. ULONG Processor = (ULONG) (NtCurrentTeb()->IdealProcessor);
  1542. PWMI_LOGGER_CONTEXT LoggerContext = EtwpLoggerContext;
  1543. //
  1544. // NOTE: This routine assumes that the caller has verified that
  1545. // EtwpLoggerContext is valid and is locked
  1546. //
  1547. if (Processor >= LoggerContext->NumberOfProcessors) {
  1548. Processor = LoggerContext->NumberOfProcessors-1;
  1549. }
  1550. #if DBG
  1551. if (LoggerContext->NumberOfProcessors == 0) {
  1552. TraceDebug(("EtwpReserveTraceBuffer: Bad Context %x\n", LoggerContext));
  1553. }
  1554. #endif
  1555. *BufferResource = NULL;
  1556. RequiredSize = (ULONG) ALIGN_TO_POWER2(RequiredSize, WmiTraceAlignment);
  1557. TryFindSpace:
  1558. //
  1559. // Get the processor specific buffer pool
  1560. //
  1561. Buffer = LoggerContext->ProcessorBuffers[Processor];
  1562. if (Buffer == NULL) {
  1563. return NULL;
  1564. }
  1565. //
  1566. // Increment refcount to buffer first to prevent it from going away
  1567. //
  1568. InterlockedIncrement(&Buffer->ReferenceCount);
  1569. if ((Buffer->Flags != BUFFER_STATE_FULL) &&
  1570. (Buffer->Flags != BUFFER_STATE_UNUSED)) {
  1571. //
  1572. // This should happen 99% of the time. Offset will have the old value
  1573. //
  1574. Offset = (ULONG) InterlockedExchangeAdd(
  1575. & Buffer->CurrentOffset, RequiredSize);
  1576. //
  1577. // First, check to see if there is enough space. If not, it will
  1578. // need to get another fresh buffer, and have the current buffer flushed
  1579. //
  1580. if (Offset+RequiredSize < LoggerContext->BufferSize) {
  1581. //
  1582. // Found the space so return it. This should happen 99% of the time
  1583. //
  1584. ReservedSpace = (PVOID) (Offset + (char*)Buffer);
  1585. if (LoggerContext->SequencePtr) {
  1586. *((PULONG) ReservedSpace) =
  1587. InterlockedIncrement(LoggerContext->SequencePtr);
  1588. }
  1589. goto FoundSpace;
  1590. }
  1591. }
  1592. else {
  1593. Offset = Buffer->CurrentOffset; // Initialize Local Variable
  1594. // tracelog.c v40 -> v41
  1595. }
  1596. if (Offset <LoggerContext->BufferSize) {
  1597. Buffer->SavedOffset = Offset; // save this for FlushBuffer
  1598. }
  1599. //
  1600. // if there is absolutely no more buffers, then return quickly
  1601. //
  1602. if ((LoggerContext->NumberOfBuffers == LoggerContext->MaximumBuffers)
  1603. && (LoggerContext->BuffersAvailable == 0)) {
  1604. goto LostEvent;
  1605. }
  1606. //
  1607. // Out of buffer space. Need to take the long route to find a buffer
  1608. //
  1609. Buffer->Flags = BUFFER_STATE_FULL;
  1610. OldBuffer = Buffer;
  1611. Buffer = EtwpSwitchBuffer(LoggerContext, OldBuffer, Processor);
  1612. if (Buffer == NULL) {
  1613. Buffer = OldBuffer;
  1614. goto LostEvent;
  1615. }
  1616. //
  1617. // Decrement the refcount that we blindly incremented earlier
  1618. // and possibly wake up the logger.
  1619. //
  1620. EtwpReleaseTraceBuffer( OldBuffer );
  1621. Buffer->ClientContext.ProcessorNumber = (UCHAR) (Processor);
  1622. goto TryFindSpace;
  1623. LostEvent:
  1624. //
  1625. // Will get here if we are throwing away events.
  1626. // from tracelog.c v36->v37
  1627. //
  1628. LoggerContext->EventsLost ++;
  1629. InterlockedDecrement(& Buffer->ReferenceCount);
  1630. Buffer = NULL;
  1631. ReservedSpace = NULL;
  1632. if (LoggerContext->SequencePtr) {
  1633. InterlockedIncrement(LoggerContext->SequencePtr);
  1634. }
  1635. FoundSpace:
  1636. //
  1637. // notify the logger after critical section
  1638. //
  1639. *BufferResource = Buffer;
  1640. return ReservedSpace;
  1641. }
  1642. //
  1643. // This Routine is called to Relog an event for straigtening out an ETL
  1644. // in time order. This will result in two events being, one for Processor
  1645. // number and the actual event without any modifications.
  1646. //
  1647. ULONG
  1648. FASTCALL
  1649. EtwpRelogEvent(
  1650. IN PWNODE_HEADER Wnode,
  1651. IN PWMI_LOGGER_CONTEXT LoggerContext
  1652. )
  1653. {
  1654. PWMI_BUFFER_HEADER BufferResource = NULL;
  1655. PEVENT_TRACE pEvent = (PEVENT_TRACE) Wnode;
  1656. PUCHAR BufferSpace;
  1657. PULONG Marker;
  1658. ULONG Size;
  1659. ULONG MaxSize;
  1660. ULONG SavedProcessor = (ULONG)NtCurrentTeb()->IdealProcessor;
  1661. ULONG Processor;
  1662. ULONG Mask;
  1663. ULONG status;
  1664. if (pEvent->Header.Size < sizeof(EVENT_TRACE) ) {
  1665. return ERROR_INVALID_PARAMETER;
  1666. }
  1667. Processor = ((PWMI_CLIENT_CONTEXT)&pEvent->ClientContext)->ProcessorNumber;
  1668. Size = pEvent->MofLength;
  1669. MaxSize = LoggerContext->BufferSize - sizeof(WMI_BUFFER_HEADER);
  1670. if ((Size == 0) || (Size > MaxSize)) {
  1671. LoggerContext->EventsLost++;
  1672. return ERROR_BUFFER_OVERFLOW;
  1673. }
  1674. NtCurrentTeb()->IdealProcessor = (BOOLEAN)Processor;
  1675. BufferSpace = (PUCHAR)
  1676. EtwpReserveTraceBuffer(
  1677. Size,
  1678. &BufferResource
  1679. );
  1680. NtCurrentTeb()->IdealProcessor = (BOOLEAN)SavedProcessor;
  1681. if (BufferSpace == NULL) {
  1682. return ERROR_NOT_ENOUGH_MEMORY;
  1683. }
  1684. RtlCopyMemory(BufferSpace, pEvent->MofData, Size);
  1685. EtwpReleaseTraceBuffer( BufferResource );
  1686. return ERROR_SUCCESS;
  1687. }
  1688. ULONG
  1689. FASTCALL
  1690. EtwpTraceUmEvent(
  1691. IN PWNODE_HEADER Wnode
  1692. )
  1693. /*++
  1694. Routine Description:
  1695. This routine is used by WMI data providers to trace events.
  1696. It expects the user to pass in the handle to the logger.
  1697. Also, the user cannot ask to log something that is larger than
  1698. the buffer size (minus buffer header).
  1699. Arguments:
  1700. Wnode The WMI node header that will be overloaded
  1701. Return Value:
  1702. STATUS_SUCCESS if the event trace is recorded successfully
  1703. --*/
  1704. {
  1705. PEVENT_TRACE_HEADER TraceRecord = (PEVENT_TRACE_HEADER) Wnode;
  1706. ULONG WnodeSize, Size, Flags, HeaderSize;
  1707. PWMI_BUFFER_HEADER BufferResource = NULL;
  1708. PWMI_LOGGER_CONTEXT LoggerContext;
  1709. ULONG Marker;
  1710. MOF_FIELD MofFields[MAX_MOF_FIELDS];
  1711. long MofCount = 0;
  1712. PCLIENT_ID Cid;
  1713. #if DBG
  1714. LONG RefCount;
  1715. #endif
  1716. HeaderSize = sizeof(WNODE_HEADER); // same size as EVENT_TRACE_HEADER
  1717. Size = Wnode->BufferSize; // take the first DWORD flags
  1718. Marker = Size;
  1719. if (Marker & TRACE_HEADER_FLAG) {
  1720. if ( ((Marker & TRACE_HEADER_ENUM_MASK) >> 16)
  1721. == TRACE_HEADER_TYPE_INSTANCE )
  1722. HeaderSize = sizeof(EVENT_INSTANCE_HEADER);
  1723. Size = TraceRecord->Size;
  1724. }
  1725. WnodeSize = Size; // WnodeSize is for the contiguous block
  1726. // Size is for what we want in buffer
  1727. Flags = Wnode->Flags;
  1728. if (!(Flags & WNODE_FLAG_LOG_WNODE) &&
  1729. !(Flags & WNODE_FLAG_TRACED_GUID))
  1730. return ERROR_INVALID_PARAMETER;
  1731. #if DBG
  1732. RefCount =
  1733. #endif
  1734. EtwpLockLogger();
  1735. #if DBG
  1736. TraceDebug(("TraceUm: %d->%d\n", RefCount-1, RefCount));
  1737. #endif
  1738. LoggerContext = EtwpLoggerContext;
  1739. if (!EtwpIsThisLoggerOn(LoggerContext)) {
  1740. #if DBG
  1741. RefCount =
  1742. #endif
  1743. EtwpUnlockLogger();
  1744. #if DBG
  1745. TraceDebug(("TraceUm: %d->%d INVALID_HANDLE\n",
  1746. RefCount+1, RefCount));
  1747. #endif
  1748. return ERROR_INVALID_HANDLE;
  1749. }
  1750. if (Flags & WNODE_FLAG_NO_HEADER) {
  1751. ULONG Status;
  1752. Status = EtwpRelogEvent( Wnode, LoggerContext );
  1753. #if DBG
  1754. RefCount =
  1755. #endif
  1756. EtwpUnlockLogger();
  1757. #if DBG
  1758. if (Status != ERROR_SUCCESS) {
  1759. TraceDebug(("TraceUm: %d->%d Relog Error \n",
  1760. RefCount+1, RefCount));
  1761. }
  1762. #endif
  1763. return Status;
  1764. }
  1765. if (Flags & WNODE_FLAG_USE_MOF_PTR) {
  1766. //
  1767. // Need to compute the total size required, since the MOF fields
  1768. // in Wnode merely contains pointers
  1769. //
  1770. long i;
  1771. PCHAR Offset = ((PCHAR)Wnode) + HeaderSize;
  1772. ULONG MofSize, MaxSize;
  1773. MaxSize = LoggerContext->BufferSize - sizeof(WMI_BUFFER_HEADER);
  1774. MofSize = WnodeSize - HeaderSize;
  1775. // allow only the maximum
  1776. if (MofSize > (sizeof(MOF_FIELD) * MAX_MOF_FIELDS))
  1777. return ERROR_INVALID_DATA;
  1778. RtlZeroMemory( MofFields, MAX_MOF_FIELDS * sizeof(MOF_FIELD));
  1779. if (MofSize > 0) {
  1780. RtlCopyMemory(MofFields, Offset, MofSize);
  1781. }
  1782. Size = HeaderSize;
  1783. MofCount = MofSize / sizeof(MOF_FIELD);
  1784. for (i=0; i<MofCount; i++) {
  1785. MofSize = MofFields[i].Length;
  1786. if (MofSize > (MaxSize - Size)) {
  1787. #if DBG
  1788. RefCount =
  1789. #endif
  1790. EtwpUnlockLogger();
  1791. #if DBG
  1792. TraceDebug(("TraceUm: %d->%d BUF_OVERFLOW1\n",
  1793. RefCount+1, RefCount));
  1794. #endif
  1795. return ERROR_BUFFER_OVERFLOW;
  1796. }
  1797. Size += MofSize;
  1798. if ((Size > MaxSize) || (Size < MofSize)) {
  1799. #if DBG
  1800. RefCount =
  1801. #endif
  1802. EtwpUnlockLogger();
  1803. #if DBG
  1804. TraceDebug(("TraceUm: %d->%d BUF_OVERFLOW2\n",
  1805. RefCount+1, RefCount));
  1806. #endif
  1807. return ERROR_BUFFER_OVERFLOW;
  1808. }
  1809. }
  1810. }
  1811. if (Size > LoggerContext->BufferSize - sizeof(WMI_BUFFER_HEADER)) {
  1812. LoggerContext->EventsLost++;
  1813. #if DBG
  1814. RefCount =
  1815. #endif
  1816. EtwpUnlockLogger();
  1817. #if DBG
  1818. TraceDebug(("TraceUm: %d->%d BUF_OVERFLOW3\n",
  1819. RefCount+1, RefCount));
  1820. #endif
  1821. return ERROR_BUFFER_OVERFLOW;
  1822. }
  1823. // So, now reserve some space in logger buffer and set that to TraceRecord
  1824. TraceRecord = (PEVENT_TRACE_HEADER)
  1825. EtwpReserveTraceBuffer(
  1826. Size,
  1827. &BufferResource
  1828. );
  1829. if (TraceRecord == NULL) {
  1830. #if DBG
  1831. RefCount =
  1832. #endif
  1833. EtwpUnlockLogger();
  1834. #if DBG
  1835. TraceDebug(("TraceUm: %d->%d NO_MEMORY\n", RefCount+1, RefCount));
  1836. #endif
  1837. return ERROR_NOT_ENOUGH_MEMORY;
  1838. }
  1839. if (Flags & WNODE_FLAG_USE_MOF_PTR) {
  1840. //
  1841. // Now we need to probe and copy all the MOF data fields
  1842. //
  1843. PVOID MofPtr;
  1844. ULONG MofLen;
  1845. long i;
  1846. PCHAR TraceOffset = ((PCHAR) TraceRecord) + HeaderSize;
  1847. RtlCopyMemory(TraceRecord, Wnode, HeaderSize);
  1848. TraceRecord->Size = (USHORT)Size; // reset to Total Size
  1849. for (i=0; i<MofCount; i++) {
  1850. MofPtr = (PVOID) MofFields[i].DataPtr;
  1851. MofLen = MofFields[i].Length;
  1852. if (MofPtr == NULL || MofLen == 0)
  1853. continue;
  1854. RtlCopyMemory(TraceOffset, MofPtr, MofLen);
  1855. TraceOffset += MofLen;
  1856. }
  1857. }
  1858. else {
  1859. RtlCopyMemory(TraceRecord, Wnode, Size);
  1860. }
  1861. if (Flags & WNODE_FLAG_USE_GUID_PTR) {
  1862. PVOID GuidPtr = (PVOID) ((PEVENT_TRACE_HEADER)Wnode)->GuidPtr;
  1863. RtlCopyMemory(&TraceRecord->Guid, GuidPtr, sizeof(GUID));
  1864. }
  1865. //
  1866. // By now, we have reserved space in the trace buffer
  1867. //
  1868. if (Marker & TRACE_HEADER_FLAG) {
  1869. if (! (WNODE_FLAG_USE_TIMESTAMP & TraceRecord->MarkerFlags) )
  1870. TraceRecord->ProcessorTime = EtwpGetCycleCount();
  1871. if (LoggerContext->UsePerfClock == EVENT_TRACE_CLOCK_PERFCOUNTER) {
  1872. TraceRecord->TimeStamp.QuadPart = TraceRecord->ProcessorTime;
  1873. }
  1874. else {
  1875. TraceRecord->TimeStamp.QuadPart = EtwpGetSystemTime();
  1876. }
  1877. Cid = &NtCurrentTeb()->ClientId;
  1878. TraceRecord->ThreadId = HandleToUlong(Cid->UniqueThread);
  1879. TraceRecord->ProcessId = HandleToUlong(Cid->UniqueProcess);
  1880. }
  1881. EtwpReleaseTraceBuffer( BufferResource );
  1882. #if DBG
  1883. RefCount =
  1884. #endif
  1885. EtwpUnlockLogger();
  1886. #if DBG
  1887. TraceDebug(("TraceUm: %d->%d\n", RefCount+1, RefCount));
  1888. #endif
  1889. return ERROR_SUCCESS;
  1890. }
  1891. PWMI_BUFFER_HEADER
  1892. FASTCALL
  1893. EtwpSwitchBuffer(
  1894. IN PWMI_LOGGER_CONTEXT LoggerContext,
  1895. IN PWMI_BUFFER_HEADER OldBuffer,
  1896. IN ULONG Processor
  1897. )
  1898. {
  1899. PWMI_BUFFER_HEADER Buffer;
  1900. ULONG CircularBufferOnly = FALSE;
  1901. //
  1902. // Need an assert for Processor
  1903. //
  1904. #if DBG
  1905. EtwpAssert( Processor < (ULONG)LoggerContext->NumberOfProcessors );
  1906. #endif
  1907. if ( (LoggerContext->LogFileMode & EVENT_TRACE_BUFFERING_MODE) &&
  1908. (LoggerContext->BufferAgeLimit.QuadPart == 0) &&
  1909. (LoggerContext->LogFileHandle == NULL) ) {
  1910. CircularBufferOnly = TRUE;
  1911. }
  1912. EtwpEnterUMCritSection();
  1913. if (OldBuffer != LoggerContext->ProcessorBuffers[Processor]) {
  1914. EtwpLeaveUMCritSection();
  1915. return OldBuffer;
  1916. }
  1917. Buffer = EtwpGetFreeBuffer(LoggerContext);
  1918. if (Buffer == NULL) {
  1919. EtwpLeaveUMCritSection();
  1920. return NULL;
  1921. }
  1922. LoggerContext->ProcessorBuffers[Processor] = Buffer;
  1923. if (CircularBufferOnly) {
  1924. InsertTailList(&LoggerContext->FreeList, &OldBuffer->Entry);
  1925. }
  1926. else {
  1927. InsertTailList(&LoggerContext->FlushList, &OldBuffer->Entry);
  1928. }
  1929. EtwpLeaveUMCritSection();
  1930. return Buffer;
  1931. }
  1932. ULONG
  1933. EtwpFreeLoggerContext(
  1934. PWMI_LOGGER_CONTEXT LoggerContext
  1935. )
  1936. {
  1937. LONG RefCount;
  1938. //
  1939. // We use LoggerEvent as a timer in EtwpFreeLoggerContext().
  1940. // This event should be set by the logger thread when it stopped.
  1941. // We need to reset it.
  1942. //
  1943. NtClearEvent(LoggerContext->LoggerEvent);
  1944. if (LoggerContext != NULL) {
  1945. LARGE_INTEGER Timeout = {(ULONG)(-300 * 1000 * 10), -1}; // 300ms
  1946. RefCount = EtwpLoggerCount;
  1947. if (RefCount > 1) {
  1948. LONG count = 0;
  1949. NTSTATUS Status = STATUS_TIMEOUT;
  1950. while (Status == STATUS_TIMEOUT) {
  1951. count ++;
  1952. Status = NtWaitForSingleObject(
  1953. EtwpLoggerContext->LoggerEvent, FALSE, &Timeout);
  1954. if (EtwpLoggerCount <= 1)
  1955. break;
  1956. if (EtwpLoggerCount == RefCount) {
  1957. #if DBG
  1958. TraceDebug(("FreeLogger: RefCount remained at %d\n",
  1959. RefCount));
  1960. #endif
  1961. if (count >= 10) {
  1962. EtwpLoggerCount = 0;
  1963. TraceDebug(("FreeLogger: Setting RefCount to 0\n"));
  1964. }
  1965. }
  1966. }
  1967. }
  1968. if (LoggerContext->BufferSpace != NULL) {
  1969. EtwpMemFree(LoggerContext->BufferSpace);
  1970. }
  1971. if (LoggerContext->ProcessorBuffers != NULL) {
  1972. EtwpFree(LoggerContext->ProcessorBuffers);
  1973. }
  1974. if (LoggerContext->LoggerName.Buffer != NULL) {
  1975. RtlFreeUnicodeString(&LoggerContext->LoggerName);
  1976. }
  1977. if (LoggerContext->LogFileName.Buffer != NULL) {
  1978. RtlFreeUnicodeString(&LoggerContext->LogFileName);
  1979. }
  1980. EtwpLoggerContext = NULL;
  1981. EtwpFree(LoggerContext);
  1982. }
  1983. return ERROR_SUCCESS;
  1984. }
  1985. ULONG
  1986. EtwpFlushAllBuffers(
  1987. IN PWMI_LOGGER_CONTEXT LoggerContext
  1988. )
  1989. {
  1990. NTSTATUS Status = STATUS_SUCCESS;
  1991. ULONG i;
  1992. ULONG NumberOfBuffers;
  1993. PLIST_ENTRY pEntry;
  1994. PWMI_BUFFER_HEADER Buffer;
  1995. ULONG RetryCount;
  1996. EtwpEnterUMCritSection();
  1997. // First, move the per processor buffer out to FlushList
  1998. //
  1999. for (i = 0; i < LoggerContext->NumberOfProcessors; i ++) {
  2000. Buffer = (PWMI_BUFFER_HEADER) LoggerContext->ProcessorBuffers[i];
  2001. LoggerContext->ProcessorBuffers[i] = NULL;
  2002. if (Buffer != NULL) {
  2003. //
  2004. // Check to see if the Buffer ReferenceCount is 0. If Yes,
  2005. // no one is writing to this buffer and it's okay to flush it.
  2006. // If No, we need to wait until the other thread is done
  2007. // writing to this buffer before flushing.
  2008. //
  2009. RetryCount = 0;
  2010. while (Buffer->ReferenceCount != 0) {
  2011. EtwpSleep (250); // Retry every 1/4 second.
  2012. RetryCount++;
  2013. if (RetryCount > 300) {
  2014. //
  2015. // Since there is no guarantee that the ReferenceCount
  2016. // will ever go down to zero, we try this for over a minute.
  2017. // After that time we continue and free the buffer
  2018. // instead of spinning for ever.
  2019. #if DBG
  2020. TraceDebug(("EtwpFlushAllBuffer: RetryCount %d exceeds limit", RetryCount));
  2021. #endif
  2022. break;
  2023. }
  2024. }
  2025. InsertTailList(& LoggerContext->FlushList, & Buffer->Entry);
  2026. }
  2027. }
  2028. NumberOfBuffers = LoggerContext->NumberOfBuffers;
  2029. while ( NT_SUCCESS(Status)
  2030. && NumberOfBuffers > 0
  2031. && ( LoggerContext->BuffersAvailable
  2032. < LoggerContext->NumberOfBuffers))
  2033. {
  2034. USHORT BufferFlag;
  2035. pEntry = IsListEmpty(& LoggerContext->FlushList)
  2036. ? NULL
  2037. : RemoveHeadList(& LoggerContext->FlushList);
  2038. if (pEntry == NULL)
  2039. break;
  2040. Buffer = CONTAINING_RECORD(pEntry, WMI_BUFFER_HEADER, Entry);
  2041. //
  2042. // Mark the last buffer with FLUSH_MARKER in order to guarantee
  2043. // writing a marked buffer even when it's empty.
  2044. // NOTE: This assumes that there is atleast one buffer in the
  2045. // FlushList at this point.
  2046. //
  2047. if ((NumberOfBuffers == 1) ||
  2048. (LoggerContext->NumberOfBuffers == LoggerContext->BuffersAvailable+1)) {
  2049. BufferFlag = WMI_BUFFER_FLAG_FLUSH_MARKER;
  2050. }
  2051. else {
  2052. BufferFlag = WMI_BUFFER_FLAG_NORMAL;
  2053. }
  2054. Status = EtwpFlushBuffer(LoggerContext, Buffer, BufferFlag);
  2055. InsertHeadList(& LoggerContext->FreeList, & Buffer->Entry);
  2056. NumberOfBuffers --;
  2057. }
  2058. // Note that LoggerContext->LogFileObject needs to remain set
  2059. // for QueryLogger to work after close
  2060. //
  2061. Status = NtClose(LoggerContext->LogFileHandle);
  2062. LoggerContext->LogFileHandle = NULL;
  2063. LoggerContext->LoggerStatus = Status;
  2064. EtwpLeaveUMCritSection();
  2065. return ERROR_SUCCESS;
  2066. }
  2067. ULONG
  2068. EtwpFlushUmLoggerBuffer()
  2069. /*++
  2070. Routine Description:
  2071. This routine is used to stop and dump the private logger buffers
  2072. when the process is shutting down (when ntdll is unloading).
  2073. LoggerThread may have been shut dowm abruptly so this routine can not
  2074. block for the LoggerThread or any other thread to release the refcount.
  2075. It is currently not used.
  2076. Arguments:
  2077. Return Value:
  2078. STATUS_SUCCESS
  2079. --*/
  2080. {
  2081. PWMI_LOGGER_CONTEXT LoggerContext;
  2082. ULONG Status = ERROR_SUCCESS;
  2083. #if DBG
  2084. LONG RefCount;
  2085. RefCount =
  2086. #endif
  2087. EtwpLockLogger();
  2088. TraceDebug(("FlushUmLoggerBuffer: %d->%d\n", RefCount-1, RefCount));
  2089. LoggerContext = EtwpLoggerContext;
  2090. if (EtwpIsThisLoggerOn(LoggerContext)) {
  2091. LoggerContext->CollectionOn = FALSE;
  2092. Status = EtwpFlushAllBuffers(LoggerContext);
  2093. if (Status == ERROR_SUCCESS) {
  2094. PWMI_LOGGER_INFORMATION EtwpLoggerInfo = NULL;
  2095. ULONG lSizeUsed;
  2096. ULONG lSizeNeeded = 0;
  2097. lSizeUsed = sizeof(WMI_LOGGER_INFORMATION)
  2098. + 2 * MAXSTR * sizeof(WCHAR);
  2099. EtwpLoggerInfo = (PWMI_LOGGER_INFORMATION) EtwpAlloc(lSizeUsed);
  2100. if (EtwpLoggerInfo == NULL) {
  2101. Status = ERROR_NOT_ENOUGH_MEMORY;
  2102. }
  2103. else {
  2104. RtlZeroMemory(EtwpLoggerInfo, lSizeUsed);
  2105. EtwpLoggerInfo->Wnode.BufferSize = lSizeUsed;
  2106. EtwpLoggerInfo->Wnode.Flags |= WNODE_FLAG_TRACED_GUID;
  2107. Status = EtwpQueryUmLogger(
  2108. EtwpLoggerInfo->Wnode.BufferSize,
  2109. & lSizeUsed,
  2110. & lSizeNeeded,
  2111. EtwpLoggerInfo);
  2112. if (Status == ERROR_SUCCESS) {
  2113. Status = EtwpFinalizeLogFileHeader(EtwpLoggerInfo);
  2114. }
  2115. EtwpFree(EtwpLoggerInfo);
  2116. }
  2117. }
  2118. #if DBG
  2119. RefCount =
  2120. #endif
  2121. EtwpUnlockLogger();
  2122. TraceDebug(("FlushUmLoggerBuffer: %d->%d\n", RefCount-1, RefCount));
  2123. EtwpFreeLoggerContext(LoggerContext);
  2124. }
  2125. return Status;
  2126. }
  2127. LONG
  2128. FASTCALL
  2129. EtwpReleaseTraceBuffer(
  2130. IN PWMI_BUFFER_HEADER BufferResource
  2131. )
  2132. {
  2133. ULONG RefCount;
  2134. if (BufferResource == NULL)
  2135. return 0;
  2136. RefCount = InterlockedDecrement(&BufferResource->ReferenceCount);
  2137. if ((RefCount == 0) && (BufferResource->Flags == BUFFER_STATE_FULL)) {
  2138. NtReleaseSemaphore(EtwpLoggerContext->Semaphore, 1, NULL);
  2139. }
  2140. return RefCount;
  2141. }
  2142. ULONG
  2143. EtwpReceiveReply(
  2144. HANDLE ReplyHandle,
  2145. ULONG ReplyCount,
  2146. ULONG ReplyIndex,
  2147. PVOID OutBuffer,
  2148. ULONG OutBufferSize
  2149. )
  2150. /*++
  2151. Routine Description:
  2152. This routine receives the replies to a CreateUM call asynchronously.
  2153. The ReplyCount and ReplyHandle are what was returned from the CreateUM
  2154. call.
  2155. It is possible to lose events (replies) in the kernel due to lack of
  2156. buffer space. The buffer is allocated once and not expanded if more
  2157. replies arrive. Kernel indicates this by setting the CountLost field to
  2158. the number of events that were lost. This is done only in a valid
  2159. response. If for some reason all responses were lost, then we will not
  2160. know the CountLost and potentiallly hang.
  2161. If a provider died before sending a response, the request object cleanup
  2162. code will send a dummy response with the ProvideId set to WmiRequestDied.
  2163. Since the caller to CreateUm does not know how many instances are present,
  2164. the OutBufferSize may not be sifficient to copy all the replies.
  2165. Therefore, we simply copy the last valid response into the OutBuffer but
  2166. indicate the number of instances of such a reply in the ProviderId field.
  2167. Arguments:
  2168. ReplyHandle Handle to the ReplyObject which receives the reply
  2169. ReplyCount Expect this many replies
  2170. ReplyIndex Index to the Array in RequestObject (not useful!)
  2171. OutBuffer Buffer to copy result to
  2172. OutBufferSize Size of the output buffer
  2173. Return Value:
  2174. STATUS_SUCCESS if the event trace is recorded successfully
  2175. --*/
  2176. {
  2177. ULONG Status = ERROR_SUCCESS;
  2178. ULONG ErrorStatus = ERROR_SUCCESS;
  2179. ULONG ReturnSize = 0;
  2180. PWMIRECEIVENOTIFICATION RcvNotification;
  2181. ULONG RcvNotificationSize;
  2182. PUCHAR Buffer;
  2183. ULONG BufferSize;
  2184. PWNODE_TOO_SMALL WnodeTooSmall;
  2185. PWNODE_HEADER Wnode;
  2186. ULONG Linkage;
  2187. ULONG RcvCount = 0;
  2188. ULONG InstanceCount=0;
  2189. ULONG CountLost;
  2190. struct {
  2191. WMIRECEIVENOTIFICATION Notification;
  2192. HANDLE3264 Handle;
  2193. } NotificationInfo;
  2194. RcvNotificationSize = sizeof(WMIRECEIVENOTIFICATION) +
  2195. sizeof(HANDLE3264);
  2196. RcvNotification = (PWMIRECEIVENOTIFICATION) &NotificationInfo;
  2197. Status = ERROR_SUCCESS;
  2198. RcvNotification->Handles[0].Handle64 = 0;
  2199. RcvNotification->Handles[0].Handle = ReplyHandle;
  2200. RcvNotification->HandleCount = 1;
  2201. RcvNotification->Action = RECEIVE_ACTION_NONE;
  2202. WmipSetPVoid3264(RcvNotification->UserModeCallback, NULL);
  2203. BufferSize = 0x2000; // Kernel default for EventQueue->Buffer
  2204. Status = ERROR_SUCCESS;
  2205. while ( (Status == ERROR_INSUFFICIENT_BUFFER) ||
  2206. ((Status == ERROR_SUCCESS) && (RcvCount < ReplyCount)) )
  2207. {
  2208. Buffer = EtwpAlloc(BufferSize);
  2209. if (Buffer != NULL)
  2210. {
  2211. Status = EtwpSendWmiKMRequest(NULL,
  2212. IOCTL_WMI_RECEIVE_NOTIFICATIONS,
  2213. RcvNotification,
  2214. RcvNotificationSize,
  2215. Buffer,
  2216. BufferSize,
  2217. &ReturnSize,
  2218. NULL);
  2219. if (Status == ERROR_SUCCESS)
  2220. {
  2221. WnodeTooSmall = (PWNODE_TOO_SMALL)Buffer;
  2222. if ((ReturnSize == sizeof(WNODE_TOO_SMALL)) &&
  2223. (WnodeTooSmall->WnodeHeader.Flags & WNODE_FLAG_TOO_SMALL))
  2224. {
  2225. //
  2226. // The buffer passed to kernel mode was too small
  2227. // so we need to make it larger and then try the
  2228. // request again
  2229. //
  2230. BufferSize = WnodeTooSmall->SizeNeeded;
  2231. Status = ERROR_INSUFFICIENT_BUFFER;
  2232. } else {
  2233. //
  2234. // We got a buffer of notifications so lets go
  2235. // process them and callback the caller
  2236. //
  2237. PUCHAR Result = (PUCHAR)OutBuffer;
  2238. ULONG SizeNeeded = 0;
  2239. ULONG SizeUsed = 0;
  2240. Wnode = (PWNODE_HEADER)Buffer;
  2241. do
  2242. {
  2243. Linkage = Wnode->Linkage;
  2244. Wnode->Linkage = 0;
  2245. if (Wnode->Flags & WNODE_FLAG_INTERNAL)
  2246. {
  2247. // If this is the Reply copy it to the buffer
  2248. PWMI_LOGGER_INFORMATION LoggerInfo;
  2249. RcvCount++;
  2250. CountLost = (Wnode->Version) >> 16;
  2251. if (CountLost > 0) {
  2252. RcvCount += CountLost;
  2253. }
  2254. if ((Wnode->ProviderId != WmiRequestDied) &&
  2255. (Wnode->BufferSize >= 2*sizeof(WNODE_HEADER))) {
  2256. LoggerInfo = (PWMI_LOGGER_INFORMATION)
  2257. ((PUCHAR)Wnode +
  2258. sizeof(WNODE_HEADER));
  2259. SizeNeeded = LoggerInfo->Wnode.BufferSize;
  2260. if (SizeNeeded <= OutBufferSize) {
  2261. PWNODE_HEADER lWnode;
  2262. InstanceCount++;
  2263. RtlCopyMemory(Result,
  2264. LoggerInfo,
  2265. LoggerInfo->Wnode.BufferSize
  2266. );
  2267. //
  2268. // Since we do not know how many instances
  2269. // got started apriori, we simply return one
  2270. // instance's status and indicate the number
  2271. // of instances in the ProviderId field.
  2272. //
  2273. lWnode = (PWNODE_HEADER) Result;
  2274. lWnode->ProviderId = InstanceCount;
  2275. }
  2276. else {
  2277. Status = ERROR_NOT_ENOUGH_MEMORY;
  2278. }
  2279. }
  2280. else {
  2281. //
  2282. // Logger had an error. Pick up the status
  2283. //
  2284. if (Wnode->BufferSize >=
  2285. sizeof(WNODE_HEADER)+sizeof(ULONG) ) {
  2286. PULONG LoggerStatus;
  2287. LoggerStatus = (PULONG) ((PUCHAR)Wnode+
  2288. sizeof(WNODE_HEADER));
  2289. ErrorStatus = *LoggerStatus;
  2290. TraceDebug(("ETW: LoggerError %d\n",
  2291. *LoggerStatus));
  2292. }
  2293. }
  2294. }
  2295. Wnode = (PWNODE_HEADER)OffsetToPtr(Wnode, Linkage);
  2296. //
  2297. // Make sure we didn't get Linkage larger than
  2298. // OutBufferSize
  2299. //
  2300. #if DBG
  2301. EtwpAssert( (ULONG)((PBYTE)Wnode - (PBYTE)Buffer) <= ReturnSize);
  2302. #endif
  2303. } while (Linkage != 0);
  2304. }
  2305. }
  2306. EtwpFree(Buffer);
  2307. } else {
  2308. Status = ERROR_NOT_ENOUGH_MEMORY;
  2309. }
  2310. }
  2311. // This can happen if all the replies we got were bad.
  2312. if (InstanceCount == 0) {
  2313. if (Status == ERROR_SUCCESS) {
  2314. Status = ErrorStatus;
  2315. }
  2316. if (Status == ERROR_SUCCESS) {
  2317. Status = ERROR_WMI_INSTANCE_NOT_FOUND;
  2318. }
  2319. }
  2320. return Status;
  2321. }
  2322. NTSTATUS
  2323. EtwpTraceUmMessage(
  2324. IN ULONG Size,
  2325. IN ULONG64 LoggerHandle,
  2326. IN ULONG MessageFlags,
  2327. IN LPGUID MessageGuid,
  2328. IN USHORT MessageNumber,
  2329. va_list MessageArgList
  2330. )
  2331. /*++
  2332. Routine Description:
  2333. Arguments:
  2334. Return Value:
  2335. --*/
  2336. {
  2337. PMESSAGE_TRACE_HEADER Header;
  2338. char * pMessageData ;
  2339. PWMI_BUFFER_HEADER BufferResource = NULL ;
  2340. ULONG SequenceNumber ;
  2341. PWMI_LOGGER_CONTEXT LoggerContext;
  2342. EtwpLockLogger(); // Lock the logger
  2343. LoggerContext = EtwpLoggerContext;
  2344. if (!EtwpIsThisLoggerOn(LoggerContext) ) {
  2345. EtwpUnlockLogger();
  2346. return STATUS_INVALID_HANDLE;
  2347. }
  2348. try {
  2349. // Figure the total size of the message including the header
  2350. Size += (MessageFlags&TRACE_MESSAGE_SEQUENCE ? sizeof(ULONG):0) +
  2351. (MessageFlags&TRACE_MESSAGE_GUID ? sizeof(GUID):0) +
  2352. (MessageFlags&TRACE_MESSAGE_COMPONENTID ? sizeof(ULONG):0) +
  2353. (MessageFlags&(TRACE_MESSAGE_TIMESTAMP | TRACE_MESSAGE_PERFORMANCE_TIMESTAMP) ? sizeof(LARGE_INTEGER):0) +
  2354. (MessageFlags&TRACE_MESSAGE_SYSTEMINFO ? 2 * sizeof(ULONG):0) +
  2355. sizeof (MESSAGE_TRACE_HEADER) ;
  2356. //
  2357. // Allocate Space in the Trace Buffer
  2358. //
  2359. if (Size > LoggerContext->BufferSize - sizeof(WMI_BUFFER_HEADER)) {
  2360. LoggerContext->EventsLost++;
  2361. EtwpUnlockLogger();
  2362. return STATUS_BUFFER_OVERFLOW;
  2363. }
  2364. if ((Header = (PMESSAGE_TRACE_HEADER)EtwpReserveTraceBuffer(Size, &BufferResource)) == NULL) {
  2365. EtwpUnlockLogger();
  2366. return STATUS_NO_MEMORY;
  2367. }
  2368. //
  2369. // Sequence Number is returned in the Marker field of the buffer
  2370. //
  2371. SequenceNumber = Header->Marker ;
  2372. //
  2373. // Now copy the necessary information into the buffer
  2374. //
  2375. Header->Marker = TRACE_MESSAGE | TRACE_HEADER_FLAG ;
  2376. //
  2377. // Fill in Header.
  2378. //
  2379. Header->Size = (USHORT)(Size & 0xFFFF) ;
  2380. Header->Packet.OptionFlags = ((USHORT)MessageFlags &
  2381. (TRACE_MESSAGE_SEQUENCE |
  2382. TRACE_MESSAGE_GUID |
  2383. TRACE_MESSAGE_COMPONENTID |
  2384. TRACE_MESSAGE_TIMESTAMP |
  2385. TRACE_MESSAGE_PERFORMANCE_TIMESTAMP |
  2386. TRACE_MESSAGE_SYSTEMINFO)) &
  2387. TRACE_MESSAGE_FLAG_MASK ;
  2388. // Message Number
  2389. Header->Packet.MessageNumber = MessageNumber ;
  2390. //
  2391. // Now add in the header options we counted.
  2392. //
  2393. pMessageData = &(((PMESSAGE_TRACE)Header)->Data);
  2394. //
  2395. // Note that the order in which these are added is critical New entries must
  2396. // be added at the end!
  2397. //
  2398. // [First Entry] Sequence Number
  2399. if (MessageFlags&TRACE_MESSAGE_SEQUENCE) {
  2400. RtlCopyMemory(pMessageData, &SequenceNumber, sizeof(ULONG)) ;
  2401. pMessageData += sizeof(ULONG) ;
  2402. }
  2403. // [Second Entry] GUID ? or CompnentID ?
  2404. if (MessageFlags&TRACE_MESSAGE_COMPONENTID) {
  2405. RtlCopyMemory(pMessageData,MessageGuid,sizeof(ULONG)) ;
  2406. pMessageData += sizeof(ULONG) ;
  2407. } else if (MessageFlags&TRACE_MESSAGE_GUID) { // Can't have both
  2408. RtlCopyMemory(pMessageData,MessageGuid,sizeof(GUID));
  2409. pMessageData += sizeof(GUID) ;
  2410. }
  2411. // [Third Entry] Timestamp?
  2412. if (MessageFlags&TRACE_MESSAGE_TIMESTAMP) {
  2413. LARGE_INTEGER Perfcount ;
  2414. if (MessageFlags&TRACE_MESSAGE_PERFORMANCE_TIMESTAMP) {
  2415. LARGE_INTEGER Frequency ;
  2416. NTSTATUS Status ;
  2417. Status = NtQueryPerformanceCounter(&Perfcount, &Frequency);
  2418. } else {
  2419. Perfcount.QuadPart = EtwpGetSystemTime();
  2420. };
  2421. RtlCopyMemory(pMessageData,&Perfcount,sizeof(LARGE_INTEGER));
  2422. pMessageData += sizeof(LARGE_INTEGER);
  2423. }
  2424. // [Fourth Entry] System Information?
  2425. if (MessageFlags&TRACE_MESSAGE_SYSTEMINFO) {
  2426. PCLIENT_ID Cid;
  2427. ULONG Id; // match with NTOS version
  2428. Cid = &NtCurrentTeb()->ClientId;
  2429. *((PULONG)pMessageData) = HandleToUlong(Cid->UniqueThread);
  2430. pMessageData += sizeof(ULONG) ;
  2431. *((PULONG)pMessageData) = HandleToUlong(Cid->UniqueProcess);
  2432. pMessageData += sizeof(ULONG) ;
  2433. }
  2434. //
  2435. // Add New Header Entries immediately before this comment!
  2436. //
  2437. //
  2438. // Now Copy in the Data.
  2439. //
  2440. { // Allocation Block
  2441. va_list ap;
  2442. PCHAR source;
  2443. ap = MessageArgList ;
  2444. while ((source = va_arg (ap, PVOID)) != NULL) {
  2445. size_t elemBytes;
  2446. elemBytes = va_arg (ap, size_t);
  2447. RtlCopyMemory (pMessageData, source, elemBytes);
  2448. pMessageData += elemBytes;
  2449. }
  2450. } // Allocation Block
  2451. //
  2452. // Buffer Complete, Release
  2453. //
  2454. EtwpReleaseTraceBuffer( BufferResource );
  2455. EtwpUnlockLogger();
  2456. //
  2457. // Return Success
  2458. //
  2459. return (STATUS_SUCCESS);
  2460. } except (EXCEPTION_EXECUTE_HANDLER) {
  2461. if (BufferResource != NULL) {
  2462. EtwpReleaseTraceBuffer ( BufferResource ); // also unlocks the logger
  2463. }
  2464. EtwpUnlockLogger();
  2465. return GetExceptionCode();
  2466. }
  2467. }
  2468. PWMI_BUFFER_HEADER
  2469. FASTCALL
  2470. EtwpGetFullFreeBuffer(
  2471. VOID
  2472. )
  2473. {
  2474. PWMI_BUFFER_HEADER Buffer;
  2475. PWMI_LOGGER_CONTEXT LoggerContext = EtwpLoggerContext;
  2476. EtwpEnterUMCritSection();
  2477. Buffer = EtwpGetFreeBuffer(LoggerContext);
  2478. if(Buffer) {
  2479. InterlockedIncrement(&Buffer->ReferenceCount);
  2480. } else {
  2481. LoggerContext->EventsLost ++;
  2482. }
  2483. EtwpLeaveUMCritSection();
  2484. return Buffer;
  2485. }
  2486. ULONG
  2487. EtwpReleaseFullBuffer(
  2488. IN PWMI_BUFFER_HEADER Buffer
  2489. )
  2490. {
  2491. PWMI_LOGGER_CONTEXT LoggerContext = EtwpLoggerContext;
  2492. ULONG CircularBufferOnly = FALSE;
  2493. if(!Buffer) return STATUS_UNSUCCESSFUL;
  2494. if ( (LoggerContext->LogFileMode & EVENT_TRACE_BUFFERING_MODE) &&
  2495. (LoggerContext->BufferAgeLimit.QuadPart == 0) &&
  2496. (LoggerContext->LogFileHandle == NULL) ) {
  2497. CircularBufferOnly = TRUE;
  2498. }
  2499. EtwpEnterUMCritSection();
  2500. Buffer->SavedOffset = Buffer->CurrentOffset;
  2501. Buffer->Flags = BUFFER_STATE_FULL;
  2502. Buffer->CurrentOffset = EtwpGetCurrentThreadId();
  2503. InterlockedDecrement(&Buffer->ReferenceCount);
  2504. if (CircularBufferOnly) {
  2505. InsertTailList(&LoggerContext->FreeList, &Buffer->Entry);
  2506. }
  2507. else {
  2508. InsertTailList(&LoggerContext->FlushList, &Buffer->Entry);
  2509. }
  2510. EtwpLeaveUMCritSection();
  2511. return ERROR_SUCCESS;
  2512. }
  2513. PWMI_BUFFER_HEADER
  2514. FASTCALL
  2515. EtwpSwitchFullBuffer(
  2516. IN PWMI_BUFFER_HEADER OldBuffer
  2517. )
  2518. {
  2519. PWMI_BUFFER_HEADER Buffer;
  2520. PWMI_LOGGER_CONTEXT LoggerContext = EtwpLoggerContext;
  2521. ULONG CircularBufferOnly = FALSE;
  2522. if ( (LoggerContext->LogFileMode & EVENT_TRACE_BUFFERING_MODE) &&
  2523. (LoggerContext->BufferAgeLimit.QuadPart == 0) &&
  2524. (LoggerContext->LogFileHandle == NULL) ) {
  2525. CircularBufferOnly = TRUE;
  2526. }
  2527. EtwpEnterUMCritSection();
  2528. Buffer = EtwpGetFullFreeBuffer();
  2529. OldBuffer->SavedOffset = OldBuffer->CurrentOffset;
  2530. OldBuffer->Flags = BUFFER_STATE_FULL;
  2531. OldBuffer->CurrentOffset = EtwpGetCurrentThreadId();
  2532. InterlockedDecrement(&OldBuffer->ReferenceCount);
  2533. if (CircularBufferOnly) {
  2534. InsertTailList(&LoggerContext->FreeList, &OldBuffer->Entry);
  2535. }
  2536. else {
  2537. InsertTailList(&LoggerContext->FlushList, &OldBuffer->Entry);
  2538. }
  2539. EtwpLeaveUMCritSection();
  2540. if (!CircularBufferOnly) {
  2541. NtReleaseSemaphore(LoggerContext->Semaphore, 1, NULL);
  2542. }
  2543. return Buffer;
  2544. }