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.

2720 lines
79 KiB

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