Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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