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.

2559 lines
78 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. traceapi.c
  5. Abstract:
  6. This is the source file that implements the published routines of
  7. the performance event tracing and logging facility. These routines are
  8. be declared in ntos\inc\wmi.h
  9. Author:
  10. Jee Fung Pang (jeepang) 03-Jan-2000
  11. Revision History:
  12. --*/
  13. #include <ntos.h>
  14. #include <evntrace.h>
  15. #include "wmikmp.h"
  16. #include <wmi.h>
  17. #include "tracep.h"
  18. extern SIZE_T MmMaximumNonPagedPoolInBytes;
  19. #ifdef ALLOC_PRAGMA
  20. #pragma alloc_text(PAGE, WmiStartTrace)
  21. #pragma alloc_text(PAGE, WmiQueryTrace)
  22. #pragma alloc_text(PAGE, WmiStopTrace)
  23. #pragma alloc_text(PAGE, WmiUpdateTrace)
  24. #pragma alloc_text(PAGE, WmiSetTraceBufferCallback)
  25. #pragma alloc_text(PAGE, WmiFlushTrace)
  26. #pragma alloc_text(PAGE, WmiQueryTraceInformation)
  27. // #pragma alloc_text(PAGEWMI, NtTraceEvent)
  28. // #pragma alloc_text(PAGEWMI, WmiTraceEvent)
  29. #pragma alloc_text(PAGEWMI, WmiTraceKernelEvent)
  30. // #pragma alloc_text(PAGEWMI, WmiTraceFastEvent)
  31. // #pragma alloc_text(PAGEWMI, WmiTraceLongEvent)
  32. // #pragma alloc_text(PAGEWMI, WmiTraceMessage)
  33. // #pragma alloc_text(PAGEWMI, WmiTraceMessageVa)
  34. #pragma alloc_text(PAGEWMI, WmiTraceUserMessage)
  35. // #pragma alloc_text(PAGEWMI, WmiGetClock)
  36. // #pragma alloc_text(PAGEWMI, WmiGetClockType)
  37. #pragma alloc_text(PAGEWMI, WmiSetMark)
  38. #endif
  39. //
  40. // Trace Control APIs
  41. //
  42. NTKERNELAPI
  43. NTSTATUS
  44. WmiStartTrace(
  45. IN OUT PWMI_LOGGER_INFORMATION LoggerInfo
  46. )
  47. /*++
  48. Routine Description:
  49. This routine is used to create and start an event tracing session.
  50. NOTE: A special instance (KERNEL_LOGGER) is reserved exclusively for
  51. logging kernel tracing.
  52. To turn on KERNEL_LOGGER, LoggerInfo->Wnode.Guid should be set to
  53. SystemTraceControlGuid, and sufficient space must be provided in
  54. LoggerInfo->LoggerName.
  55. To turn on other loggers, simply provide a name in LoggerName. The
  56. logger id will be returned.
  57. Arguments:
  58. LoggerInfo a pointer to the structure for the logger's control
  59. and status information
  60. Return Value:
  61. The status of performing the action requested.
  62. --*/
  63. {
  64. NTSTATUS status;
  65. PWCHAR LogFileName = NULL;
  66. HANDLE FileHandle = NULL;
  67. ULONG DelayOpen;
  68. PAGED_CODE();
  69. if (LoggerInfo == NULL)
  70. return STATUS_INVALID_PARAMETER;
  71. //
  72. // We assume that the caller is always kernel mode
  73. // First, we try and see it is a delay create.
  74. // If not, if we can even open the file
  75. //
  76. DelayOpen = LoggerInfo->LogFileMode & EVENT_TRACE_DELAY_OPEN_FILE_MODE;
  77. if (!DelayOpen) {
  78. if (LoggerInfo->LogFileName.Buffer != NULL) { // && !delay_create
  79. status = WmipCreateNtFileName(
  80. LoggerInfo->LogFileName.Buffer,
  81. &LogFileName);
  82. if (!NT_SUCCESS(status))
  83. return status;
  84. status = WmipCreateDirectoryFile(LogFileName,
  85. FALSE,
  86. &FileHandle,
  87. LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_APPEND);
  88. if (LogFileName != NULL) {
  89. ExFreePool(LogFileName);
  90. }
  91. if (!NT_SUCCESS(status)) {
  92. return status;
  93. }
  94. ZwClose(FileHandle);
  95. }
  96. }
  97. status = WmipStartLogger(LoggerInfo);
  98. if (NT_SUCCESS(status)) {
  99. status = WmiFlushTrace(LoggerInfo);
  100. }
  101. return status;
  102. }
  103. NTKERNELAPI
  104. NTSTATUS
  105. WmiQueryTrace(
  106. IN OUT PWMI_LOGGER_INFORMATION LoggerInfo
  107. )
  108. /*++
  109. Routine Description:
  110. This routine is called to query the status of a tracing session.
  111. Caller must pass in either the Logger Name or a valid Logger Id/Handle.
  112. Arguments:
  113. LoggerInfo a pointer to the structure for the logger's control
  114. and status information
  115. Return Value:
  116. The status of performing the action requested.
  117. --*/
  118. {
  119. PAGED_CODE();
  120. if (LoggerInfo == NULL)
  121. return STATUS_INVALID_PARAMETER;
  122. return WmipQueryLogger(LoggerInfo, NULL);
  123. }
  124. NTKERNELAPI
  125. NTSTATUS
  126. WmiStopTrace(
  127. IN PWMI_LOGGER_INFORMATION LoggerInfo
  128. )
  129. /*++
  130. Routine Description:
  131. It is called by WmipIoControl in wmi.c, with IOCTL_WMI_STOP_LOGGER
  132. to stop an instance of the logger. If the logger is the kernel logger,
  133. it will also turn off kernel tracing and unlock the routines previously
  134. locked. It will also free all the context of the logger.
  135. Calls StopLoggerInstance to do the actual work.
  136. Arguments:
  137. LoggerInfo a pointer to the structure for the logger's control
  138. and status information
  139. Return Value:
  140. The status of performing the action requested.
  141. --*/
  142. {
  143. PWMI_LOGGER_CONTEXT LoggerContext = NULL;
  144. NTSTATUS Status;
  145. LARGE_INTEGER TimeOut = {(ULONG)(-200 * 1000 * 1000 * 10), -1};
  146. ACCESS_MASK DesiredAccess = TRACELOG_GUID_ENABLE;
  147. ULONG LoggerId;
  148. #if DBG
  149. LONG RefCount;
  150. #endif
  151. PAGED_CODE();
  152. if (LoggerInfo == NULL)
  153. return STATUS_INVALID_PARAMETER;
  154. TraceDebug((1, "WmiStopTrace: %d\n",
  155. LoggerInfo->Wnode.HistoricalContext));
  156. #if DBG
  157. Status = WmipVerifyLoggerInfo(LoggerInfo, &LoggerContext, "WmiStopTrace");
  158. #else
  159. Status = WmipVerifyLoggerInfo(LoggerInfo, &LoggerContext);
  160. #endif
  161. if (!NT_SUCCESS(Status) || (LoggerContext == NULL))
  162. return Status;
  163. LoggerId = LoggerContext->LoggerId;
  164. TraceDebug((1, "WmiStopTrace: Stopping %X %d slot %X\n",
  165. LoggerContext, LoggerId, WmipLoggerContext[LoggerId]));
  166. if (LoggerContext->KernelTraceOn)
  167. DesiredAccess |= TRACELOG_ACCESS_KERNEL_LOGGER;
  168. Status = WmipCheckGuidAccess(
  169. (LPGUID) &EventTraceGuid,
  170. DesiredAccess
  171. );
  172. if (!NT_SUCCESS(Status)) {
  173. #ifndef WMI_MUTEX_FREE
  174. InterlockedDecrement(&LoggerContext->MutexCount);
  175. TraceDebug((1, "WmiStopTrace: Release mutex1 %d %d\n",
  176. LoggerId, LoggerContext->MutexCount));
  177. WmipReleaseMutex(&LoggerContext->LoggerMutex);
  178. #endif
  179. #if DBG
  180. RefCount =
  181. #endif
  182. WmipDereferenceLogger(LoggerId);
  183. TraceDebug((1, "WmiStopTrace: Status1=%X %d %d->%d\n",
  184. Status, LoggerId, RefCount+1, RefCount));
  185. return Status;
  186. }
  187. if (!IsEqualGUID(&LoggerContext->InstanceGuid, &EventTraceGuid)) {
  188. Status = WmipCheckGuidAccess(
  189. (LPGUID) &LoggerContext->InstanceGuid,
  190. DesiredAccess
  191. );
  192. if (!NT_SUCCESS(Status)) {
  193. #ifndef WMI_MUTEX_FREE
  194. InterlockedDecrement(&LoggerContext->MutexCount);
  195. TraceDebug((1, "WmiStopTrace: Release mutex2 %d %d\n",
  196. LoggerId, LoggerContext->MutexCount));
  197. WmipReleaseMutex(&LoggerContext->LoggerMutex);
  198. #endif
  199. #if DBG
  200. RefCount =
  201. #endif
  202. WmipDereferenceLogger(LoggerId);
  203. TraceDebug((1, "WmiStopTrace: Status2=%X %d %d->%d\n",
  204. Status, LoggerId, RefCount+1, RefCount));
  205. return Status;
  206. }
  207. }
  208. //
  209. // Reset the Event inside the mutex to be sure
  210. // before waiting on it.
  211. KeResetEvent(&LoggerContext->FlushEvent);
  212. Status = WmipStopLoggerInstance (LoggerContext);
  213. #ifndef WMI_MUTEX_FREE
  214. InterlockedDecrement(&LoggerContext->MutexCount);
  215. TraceDebug((1, "WmiStopTrace: Release mutex3 %d %d\n",
  216. LoggerId, LoggerContext->MutexCount));
  217. WmipReleaseMutex(&LoggerContext->LoggerMutex); // Let others in
  218. #endif
  219. if (NT_SUCCESS(Status)) {
  220. LIST_ENTRY TraceGuidMap;
  221. InitializeListHead(&TraceGuidMap);
  222. if (LoggerId == WmipKernelLogger)
  223. WmipKernelLogger = KERNEL_LOGGER;
  224. else if (LoggerId == WmipEventLogger)
  225. WmipEventLogger = 0XFFFFFFFF;
  226. else
  227. Status = WmipDisableTraceProviders(LoggerId, &TraceGuidMap );
  228. if (LoggerInfo != NULL) {
  229. ULONG GuidMapBuffers = 0;
  230. if (NT_SUCCESS(LoggerContext->LoggerStatus)) {
  231. LONG Buffers;
  232. Status = STATUS_TIMEOUT;
  233. Buffers = LoggerContext->BuffersAvailable;
  234. //
  235. // If all buffers are accounted for and the logfile handle
  236. // is NULL, then there is no reason to wait.
  237. //
  238. if ( (Buffers == LoggerContext->NumberOfBuffers) &&
  239. (LoggerContext->LogFileHandle == NULL) ) {
  240. Status = STATUS_SUCCESS;
  241. }
  242. //
  243. // We need to wait for the logger thread to flush
  244. //
  245. while (Status == STATUS_TIMEOUT) {
  246. Status = KeWaitForSingleObject(
  247. &LoggerContext->FlushEvent,
  248. Executive,
  249. KernelMode,
  250. FALSE,
  251. &TimeOut
  252. );
  253. /* if (LoggerContext->NumberOfBuffers
  254. == LoggerContext->BuffersAvailable)
  255. break;
  256. else if (LoggerContext->BuffersAvailable == Buffers) {
  257. TraceDebug((1,
  258. "WmiStopTrace: Logger %d hung %d != %d\n",
  259. LoggerId, Buffers, LoggerContext->NumberOfBuffers));
  260. KeResetEvent(&LoggerContext->FlushEvent);
  261. // break;
  262. }
  263. */
  264. TraceDebug((1, "WmiStopTrace: Wait status=%X\n",Status));
  265. }
  266. }
  267. //
  268. // For application loggers, dump the guidmap at the end.
  269. //
  270. if ( (LoggerId != WmipKernelLogger) &&
  271. (LoggerId != WmipEventLogger) &&
  272. (! IsListEmpty(&TraceGuidMap) ) )
  273. {
  274. GuidMapBuffers = WmipDumpGuidMaps(LoggerContext, &TraceGuidMap);
  275. }
  276. //
  277. // Required for Query to work
  278. // But since CollectionOn is FALSE, it should be safe
  279. //
  280. Status = WmipQueryLogger(
  281. LoggerInfo,
  282. LoggerContext
  283. );
  284. LoggerInfo->Checksum64 = GuidMapBuffers;
  285. }
  286. KeSetEvent(&LoggerContext->LoggerEvent, 0, FALSE); // release context
  287. }
  288. #if DBG
  289. RefCount =
  290. #endif
  291. WmipDereferenceLogger(LoggerId);
  292. TraceDebug((1, "WmiStopTrace: Stopped status=%X %d %d->%d\n",
  293. Status, LoggerId, RefCount+1, RefCount));
  294. return Status;
  295. }
  296. NTKERNELAPI
  297. NTSTATUS
  298. WmiUpdateTrace(
  299. IN OUT PWMI_LOGGER_INFORMATION LoggerInfo
  300. )
  301. /*++
  302. Routine Description:
  303. It is called by WmipIoControl in wmi.c, with IOCTL_WMI_UPDATE_LOGGER
  304. to update certain characteristics of a running logger.
  305. Arguments:
  306. LoggerInfo a pointer to the structure for the logger's control
  307. and status information
  308. Return Value:
  309. The status of performing the action requested.
  310. --*/
  311. {
  312. NTSTATUS Status;
  313. ULONG Max_Buffers;
  314. PWMI_LOGGER_CONTEXT LoggerContext = NULL;
  315. LARGE_INTEGER OneSecond = {(ULONG)(-1 * 1000 * 1000 * 10), -1};
  316. ACCESS_MASK DesiredAccess = TRACELOG_GUID_ENABLE;
  317. LARGE_INTEGER TimeOut = {(ULONG)(-20 * 1000 * 1000 * 10), -1};
  318. ULONG EnableFlags, TmpFlags;
  319. KPROCESSOR_MODE RequestorMode;
  320. ULONG LoggerMode, LoggerId, NewMode;
  321. UNICODE_STRING NewLogFileName;
  322. UNICODE_STRING OldFilePattern;
  323. PTRACE_ENABLE_FLAG_EXTENSION FlagExt;
  324. PERFINFO_GROUPMASK *PerfGroupMasks=NULL;
  325. ULONG GroupMaskSize;
  326. SECURITY_QUALITY_OF_SERVICE ServiceQos;
  327. #if DBG
  328. LONG RefCount;
  329. #endif
  330. PAGED_CODE();
  331. //
  332. // see if Logger is running properly first. Error checking will be done
  333. // in WmiQueryTrace
  334. //
  335. if (LoggerInfo == NULL)
  336. return STATUS_INVALID_PARAMETER;
  337. EnableFlags = LoggerInfo->EnableFlags;
  338. TraceDebug((1, "WmiUpdateTrace: %d\n",
  339. LoggerInfo->Wnode.HistoricalContext));
  340. #if DBG
  341. Status = WmipVerifyLoggerInfo(LoggerInfo, &LoggerContext, "WmiUpdateTrace");
  342. #else
  343. Status = WmipVerifyLoggerInfo(LoggerInfo, &LoggerContext);
  344. #endif
  345. if (!NT_SUCCESS(Status) || (LoggerContext == NULL))
  346. return Status;
  347. OldFilePattern.Buffer = NULL;
  348. LoggerId = LoggerContext->LoggerId;
  349. // at this point, LoggerContext must be non-NULL
  350. LoggerMode = LoggerContext->LoggerMode; // local copy
  351. NewMode = LoggerInfo->LogFileMode;
  352. //
  353. // First, check to make sure that you cannot turn on certain modes
  354. // in UpdateTrace()
  355. //
  356. if ( ((NewMode & EVENT_TRACE_FILE_MODE_SEQUENTIAL) &&
  357. (NewMode & EVENT_TRACE_FILE_MODE_CIRCULAR)) ||
  358. ((NewMode & EVENT_TRACE_USE_GLOBAL_SEQUENCE) &&
  359. (NewMode & EVENT_TRACE_USE_LOCAL_SEQUENCE)) ||
  360. (!(LoggerMode & EVENT_TRACE_FILE_MODE_CIRCULAR) &&
  361. (NewMode & EVENT_TRACE_FILE_MODE_CIRCULAR)) ||
  362. // Cannot support append to circular
  363. ((NewMode & EVENT_TRACE_FILE_MODE_CIRCULAR) &&
  364. (NewMode & EVENT_TRACE_FILE_MODE_APPEND))
  365. ) {
  366. #ifndef WMI_MUTEX_FREE
  367. InterlockedDecrement(&LoggerContext->MutexCount);
  368. TraceDebug((1, "WmiUpdateTrace: Release mutex1 %d %d\n",
  369. LoggerContext->LoggerId, LoggerContext->MutexCount));
  370. WmipReleaseMutex(&LoggerContext->LoggerMutex);
  371. #endif
  372. #if DBG
  373. RefCount =
  374. #endif
  375. WmipDereferenceLogger(LoggerId);
  376. TraceDebug((1, "WmiUpdateTrace: Status2=%X %d %d->%d\n",
  377. Status, LoggerId, RefCount+1, RefCount));
  378. return STATUS_INVALID_PARAMETER;
  379. }
  380. //
  381. // support turn on or off real time dynamically
  382. //
  383. if (NewMode & EVENT_TRACE_REAL_TIME_MODE) {
  384. LoggerMode |= EVENT_TRACE_REAL_TIME_MODE;
  385. DesiredAccess |= TRACELOG_CREATE_REALTIME;
  386. } else {
  387. if (LoggerMode & EVENT_TRACE_REAL_TIME_MODE)
  388. DesiredAccess |= TRACELOG_CREATE_REALTIME; // turn off real time
  389. LoggerMode &= ~EVENT_TRACE_REAL_TIME_MODE;
  390. }
  391. if (NewMode & EVENT_TRACE_BUFFERING_MODE) {
  392. LoggerMode |= EVENT_TRACE_BUFFERING_MODE;
  393. }
  394. else {
  395. LoggerMode &= ~EVENT_TRACE_BUFFERING_MODE;
  396. }
  397. if (LoggerContext->KernelTraceOn)
  398. DesiredAccess |= TRACELOG_ACCESS_KERNEL_LOGGER;
  399. if (LoggerInfo->LogFileHandle != NULL)
  400. DesiredAccess |= TRACELOG_CREATE_ONDISK;
  401. Status = WmipCheckGuidAccess(
  402. (LPGUID) &EventTraceGuid,
  403. DesiredAccess
  404. );
  405. if (!NT_SUCCESS(Status)) {
  406. #ifndef WMI_MUTEX_FREE
  407. InterlockedDecrement(&LoggerContext->MutexCount);
  408. TraceDebug((1, "WmiUpdateTrace: Release mutex1 %d %d\n",
  409. LoggerContext->LoggerId, LoggerContext->MutexCount));
  410. WmipReleaseMutex(&LoggerContext->LoggerMutex);
  411. #endif
  412. #if DBG
  413. RefCount =
  414. #endif
  415. WmipDereferenceLogger(LoggerId);
  416. TraceDebug((1, "WmiUpdateTrace: Status2=%X %d %d->%d\n",
  417. Status, LoggerId, RefCount+1, RefCount));
  418. return Status;
  419. }
  420. if (!IsEqualGUID(&LoggerContext->InstanceGuid, &EventTraceGuid)) {
  421. Status = WmipCheckGuidAccess(
  422. (LPGUID) &LoggerContext->InstanceGuid,
  423. DesiredAccess
  424. );
  425. if (!NT_SUCCESS(Status)) {
  426. #ifndef WMI_MUTEX_FREE
  427. InterlockedDecrement(&LoggerContext->MutexCount);
  428. TraceDebug((1, "WmiUpdateTrace: Release mutex2 %d %d\n",
  429. LoggerId, LoggerContext->MutexCount));
  430. WmipReleaseMutex(&LoggerContext->LoggerMutex);
  431. #endif
  432. #if DBG
  433. RefCount =
  434. #endif
  435. WmipDereferenceLogger(LoggerId);
  436. TraceDebug((1, "WmiUpdateTrace: Status3=%X %d %d->%d\n",
  437. Status, LoggerId,
  438. RefCount+1, RefCount));
  439. return Status;
  440. }
  441. }
  442. RtlZeroMemory(&NewLogFileName, sizeof(UNICODE_STRING));
  443. RequestorMode = KeGetPreviousMode();
  444. if (LoggerInfo->LogFileHandle != NULL) {
  445. PFILE_OBJECT fileObject;
  446. OBJECT_HANDLE_INFORMATION handleInformation;
  447. ACCESS_MASK grantedAccess;
  448. BOOLEAN bDelayOpenFlag = FALSE;
  449. bDelayOpenFlag = (LoggerContext->LogFileHandle == NULL &&
  450. (LoggerContext->LoggerMode & EVENT_TRACE_DELAY_OPEN_FILE_MODE));
  451. if (LoggerInfo->LogFileName.Buffer == NULL) {
  452. Status = STATUS_INVALID_PARAMETER;
  453. goto ReleaseAndExit;
  454. }
  455. // Save the new LogFileName
  456. //
  457. try {
  458. if (RequestorMode != KernelMode) {
  459. ProbeForRead(
  460. LoggerInfo->LogFileName.Buffer,
  461. LoggerInfo->LogFileName.Length,
  462. sizeof (UCHAR) );
  463. }
  464. RtlCreateUnicodeString(
  465. &NewLogFileName,
  466. LoggerInfo->LogFileName.Buffer);
  467. }
  468. except (EXCEPTION_EXECUTE_HANDLER) {
  469. if (NewLogFileName.Buffer != NULL) {
  470. RtlFreeUnicodeString(&NewLogFileName);
  471. }
  472. #ifndef WMI_MUTEX_FREE
  473. InterlockedDecrement(&LoggerContext->MutexCount);
  474. TraceDebug((1, "WmiUpdateTrace: Release mutex3 %d %d\n",
  475. LoggerId, LoggerContext->MutexCount));
  476. WmipReleaseMutex(&LoggerContext->LoggerMutex);
  477. #endif
  478. #if DBG
  479. RefCount =
  480. #endif
  481. WmipDereferenceLogger(LoggerId);
  482. TraceDebug((1, "WmiUpdateTrace: Status5=EXCEPTION %d %d->%d\n",
  483. LoggerId, RefCount+1, RefCount));
  484. return GetExceptionCode();
  485. }
  486. // Switching to a new logfile. This routine does not put any
  487. // headers into the logfile. The headers should be written out
  488. // by UpdateTrace() in user-mode.
  489. //
  490. fileObject = NULL;
  491. Status = ObReferenceObjectByHandle(
  492. LoggerInfo->LogFileHandle,
  493. 0L,
  494. IoFileObjectType,
  495. RequestorMode,
  496. (PVOID *) &fileObject,
  497. &handleInformation);
  498. if (!NT_SUCCESS(Status)) {
  499. goto ReleaseAndExit;
  500. }
  501. if (RequestorMode != KernelMode) {
  502. grantedAccess = handleInformation.GrantedAccess;
  503. if (!SeComputeGrantedAccesses(grantedAccess, FILE_WRITE_DATA)) {
  504. ObDereferenceObject( fileObject );
  505. Status = STATUS_ACCESS_DENIED;
  506. goto ReleaseAndExit;
  507. }
  508. }
  509. ObDereferenceObject(fileObject); // Referenced in WmipCreateLogFile
  510. // Obtain the security context here so we can use it
  511. // later to impersonate the user, which we will do
  512. // if we cannot access the file as SYSTEM. This
  513. // usually occurs if the file is on a remote machine.
  514. //
  515. ServiceQos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  516. ServiceQos.ImpersonationLevel = SecurityImpersonation;
  517. ServiceQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  518. ServiceQos.EffectiveOnly = TRUE;
  519. Status = SeCreateClientSecurity(
  520. CONTAINING_RECORD(KeGetCurrentThread(), ETHREAD, Tcb),
  521. &ServiceQos,
  522. FALSE,
  523. & LoggerContext->ClientSecurityContext);
  524. if (!NT_SUCCESS(Status)) {
  525. goto ReleaseAndExit;
  526. }
  527. if (LoggerInfo->Checksum != NULL) {
  528. if (LoggerContext->LoggerHeader == NULL) {
  529. LoggerContext->LoggerHeader =
  530. ExAllocatePoolWithTag(
  531. PagedPool,
  532. sizeof(WNODE_HEADER) + sizeof(TRACE_LOGFILE_HEADER),
  533. TRACEPOOLTAG);
  534. }
  535. if (LoggerContext->LoggerHeader != NULL) {
  536. RtlCopyMemory(
  537. LoggerContext->LoggerHeader,
  538. LoggerInfo->Checksum,
  539. sizeof(WNODE_HEADER) + sizeof(TRACE_LOGFILE_HEADER));
  540. }
  541. }
  542. // We try to update the file name using LoggerContext->NewLogFileName.
  543. // This is freed by WmipCreateLogFile() in the logger thread.
  544. // This have to be NULL.
  545. if (NewLogFileName.Buffer != NULL) {
  546. if (NewMode & EVENT_TRACE_FILE_MODE_NEWFILE) {
  547. if (LoggerContext->LogFilePattern.Buffer != NULL) {
  548. OldFilePattern = LoggerContext->LogFilePattern;
  549. }
  550. LoggerContext->LogFilePattern = NewLogFileName;
  551. LoggerContext->LoggerMode |= EVENT_TRACE_FILE_MODE_NEWFILE;
  552. LoggerMode |= EVENT_TRACE_FILE_MODE_NEWFILE;
  553. }
  554. else {
  555. ASSERT(LoggerContext->NewLogFileName.Buffer == NULL);
  556. LoggerContext->NewLogFileName = NewLogFileName;
  557. }
  558. }
  559. else {
  560. Status = STATUS_INVALID_PARAMETER;
  561. goto ReleaseAndExit;
  562. }
  563. //
  564. // Reset the event inside the mutex before waiting on it.
  565. //
  566. KeResetEvent(&LoggerContext->FlushEvent);
  567. ZwClose(LoggerInfo->LogFileHandle);
  568. LoggerInfo->LogFileHandle = NULL;
  569. // must turn on flag just before releasing semaphore
  570. LoggerContext->RequestFlag |= REQUEST_FLAG_NEW_FILE;
  571. // Wake up the logger thread (system) to change the file
  572. Status = WmipNotifyLogger(LoggerContext);
  573. if (!NT_SUCCESS(Status)) {
  574. goto ReleaseAndExit;
  575. }
  576. // use the same event initialized by start logger
  577. //
  578. KeWaitForSingleObject(
  579. &LoggerContext->FlushEvent,
  580. Executive,
  581. KernelMode,
  582. FALSE,
  583. &TimeOut
  584. );
  585. KeResetEvent(&LoggerContext->FlushEvent);
  586. Status = LoggerContext->LoggerStatus;
  587. if (!NT_SUCCESS(Status) || !LoggerContext->CollectionOn) {
  588. goto ReleaseAndExit;
  589. }
  590. if (bDelayOpenFlag && (LoggerContext->LoggerId == WmipKernelLogger)) {
  591. LONG PerfLogInTransition;
  592. //
  593. // This is a update call from advapi32.dll after RunDown.
  594. // Call PerfInfoStartLog.
  595. //
  596. if (EnableFlags & EVENT_TRACE_FLAG_EXTENSION) {
  597. FlagExt = (PTRACE_ENABLE_FLAG_EXTENSION) &EnableFlags;
  598. if ((FlagExt->Length == 0) || (FlagExt->Offset == 0)) {
  599. Status = STATUS_INVALID_PARAMETER;
  600. goto ReleaseAndExit;
  601. }
  602. if ((FlagExt->Length * sizeof(ULONG)) >
  603. (LoggerInfo->Wnode.BufferSize - FlagExt->Offset)) {
  604. Status = STATUS_INVALID_PARAMETER;
  605. goto ReleaseAndExit;
  606. }
  607. GroupMaskSize = FlagExt->Length * sizeof(ULONG);
  608. if (GroupMaskSize < sizeof(PERFINFO_GROUPMASK)) {
  609. GroupMaskSize = sizeof(PERFINFO_GROUPMASK);
  610. }
  611. } else {
  612. GroupMaskSize = sizeof(PERFINFO_GROUPMASK);
  613. }
  614. LoggerContext->EnableFlagArray = (PULONG) WmipExtendBase(LoggerContext, GroupMaskSize);
  615. if (LoggerContext->EnableFlagArray) {
  616. PCHAR FlagArray;
  617. RtlZeroMemory(LoggerContext->EnableFlagArray, GroupMaskSize);
  618. if (EnableFlags & EVENT_TRACE_FLAG_EXTENSION) {
  619. FlagArray = (PCHAR) (FlagExt->Offset + (PCHAR) LoggerInfo);
  620. //
  621. // Copy only the bytes actually supplied
  622. //
  623. RtlCopyMemory(LoggerContext->EnableFlagArray, FlagArray, FlagExt->Length * sizeof(ULONG));
  624. EnableFlags = LoggerContext->EnableFlagArray[0];
  625. } else {
  626. LoggerContext->EnableFlagArray[0] = EnableFlags;
  627. }
  628. PerfLogInTransition =
  629. InterlockedCompareExchange(&LoggerContext->PerfLogInTransition,
  630. PERF_LOG_START_TRANSITION,
  631. PERF_LOG_NO_TRANSITION);
  632. if (PerfLogInTransition != PERF_LOG_NO_TRANSITION) {
  633. Status = STATUS_ALREADY_DISCONNECTED;
  634. goto ReleaseAndExit;
  635. }
  636. PerfGroupMasks = (PERFINFO_GROUPMASK *) &LoggerContext->EnableFlagArray[0];
  637. Status = PerfInfoStartLog(PerfGroupMasks, PERFINFO_START_LOG_POST_BOOT);
  638. PerfLogInTransition =
  639. InterlockedExchange(&LoggerContext->PerfLogInTransition,
  640. PERF_LOG_NO_TRANSITION);
  641. ASSERT(PerfLogInTransition == PERF_LOG_START_TRANSITION);
  642. if (!NT_SUCCESS(Status)) {
  643. goto ReleaseAndExit;
  644. }
  645. } else {
  646. Status = STATUS_NO_MEMORY;
  647. goto ReleaseAndExit;
  648. }
  649. }
  650. }
  651. if (LoggerContext->KernelTraceOn &&
  652. LoggerId == WmipKernelLogger &&
  653. IsEqualGUID(&LoggerInfo->Wnode.Guid, &SystemTraceControlGuid)) {
  654. TmpFlags = (~LoggerContext->EnableFlags & EnableFlags);
  655. if (TmpFlags != 0) {
  656. WmipEnableKernelTrace(TmpFlags);
  657. }
  658. TmpFlags = (LoggerContext->EnableFlags & ~EnableFlags);
  659. if (TmpFlags != 0) {
  660. WmipDisableKernelTrace(TmpFlags);
  661. }
  662. LoggerContext->EnableFlags = EnableFlags;
  663. }
  664. //
  665. // Cap Maximum Buffers to Max_Buffers
  666. //
  667. if ( LoggerInfo->MaximumBuffers > 0 ) {
  668. Max_Buffers = (LoggerContext->BufferSize > 0) ?
  669. (ULONG) (MmMaximumNonPagedPoolInBytes
  670. / TRACE_MAXIMUM_NP_POOL_USAGE
  671. / LoggerContext->BufferSize)
  672. : 0;
  673. if (LoggerInfo->MaximumBuffers > Max_Buffers ) {
  674. LoggerInfo->MaximumBuffers = Max_Buffers;
  675. }
  676. if (LoggerInfo->MaximumBuffers > LoggerContext->MaximumBuffers) {
  677. LoggerContext->MaximumBuffers = LoggerInfo->MaximumBuffers;
  678. }
  679. }
  680. #ifdef NTPERF
  681. if (PERFINFO_IS_LOGGING_TO_PERFMEM()) {
  682. //
  683. // Logging to Perfmem. The Maximum should be the perfmem size.
  684. //
  685. LoggerContext->MaximumBuffers = PerfQueryBufferSizeBytes()/LoggerContext->BufferSize;
  686. }
  687. #endif //NTPERF
  688. // Allow changing of FlushTimer
  689. if (LoggerInfo->FlushTimer > 0) {
  690. #ifdef WMI_NON_BLOCKING
  691. LoggerContext->FlushTimer = LoggerInfo->FlushTimer;
  692. #else
  693. LoggerContext->FlushTimer.QuadPart =
  694. LoggerInfo->FlushTimer * OneSecond.QuadPart;
  695. #endif //WMI_NON_BLOCKING
  696. }
  697. if (OldFilePattern.Buffer != NULL) {
  698. RtlFreeUnicodeString(&OldFilePattern);
  699. }
  700. if (NewMode & EVENT_TRACE_KD_FILTER_MODE) {
  701. LoggerMode |= EVENT_TRACE_KD_FILTER_MODE;
  702. LoggerContext->BufferCallback = &KdReportTraceData;
  703. }
  704. else {
  705. LoggerMode &= ~EVENT_TRACE_KD_FILTER_MODE;
  706. if (LoggerContext->BufferCallback == &KdReportTraceData) {
  707. LoggerContext->BufferCallback = NULL;
  708. }
  709. }
  710. if (LoggerContext->LoggerMode & EVENT_TRACE_DELAY_OPEN_FILE_MODE) {
  711. LoggerContext->LoggerMode = LoggerMode;
  712. }
  713. else {
  714. LoggerContext->LoggerMode =
  715. (LoggerMode & ~EVENT_TRACE_DELAY_OPEN_FILE_MODE);
  716. }
  717. Status = WmipQueryLogger(LoggerInfo, LoggerContext);
  718. ReleaseAndExit:
  719. #ifndef WMI_MUTEX_FREE
  720. InterlockedDecrement(&LoggerContext->MutexCount);
  721. TraceDebug((1, "WmiUpdateTrace: Release mutex5 %d %d\n",
  722. LoggerId, LoggerContext->MutexCount));
  723. WmipReleaseMutex(&LoggerContext->LoggerMutex);
  724. #endif
  725. #if DBG
  726. RefCount =
  727. #endif
  728. WmipDereferenceLogger(LoggerId);
  729. TraceDebug((1, "WmiUpdateTrace: %d %d->%d\n",
  730. LoggerId, RefCount+1, RefCount));
  731. return Status;
  732. }
  733. NTKERNELAPI
  734. NTSTATUS
  735. WmiFlushTrace(
  736. IN OUT PWMI_LOGGER_INFORMATION LoggerInfo
  737. )
  738. /*++
  739. Routine Description:
  740. It is called by WmipIoControl in wmi.c, with IOCTL_WMI_FLUSH_LOGGER
  741. to flush all the buffers out of a particular logger
  742. Arguments:
  743. LoggerInfo a pointer to the structure for the logger's control
  744. and status information
  745. Return Value:
  746. The status of performing the action requested.
  747. --*/
  748. {
  749. NTSTATUS Status;
  750. PWMI_LOGGER_CONTEXT LoggerContext = NULL;
  751. ULONG LoggerId;
  752. #if DBG
  753. LONG RefCount;
  754. #endif
  755. PAGED_CODE();
  756. //
  757. // see if Logger is running properly first. Error checking will be done
  758. // in WmiQueryTrace
  759. //
  760. if (LoggerInfo == NULL)
  761. return STATUS_INVALID_PARAMETER;
  762. TraceDebug((1, "WmiFlushTrace: %d\n",
  763. LoggerInfo->Wnode.HistoricalContext));
  764. #if DBG
  765. Status = WmipVerifyLoggerInfo(LoggerInfo, &LoggerContext, "WmiFlushTrace");
  766. #else
  767. Status = WmipVerifyLoggerInfo(LoggerInfo, &LoggerContext);
  768. #endif
  769. if (!NT_SUCCESS(Status) || (LoggerContext == NULL))
  770. return Status;
  771. LoggerId = LoggerContext->LoggerId;
  772. Status = WmipFlushLogger(LoggerContext, TRUE);
  773. if (NT_SUCCESS(Status)) {
  774. Status = WmipQueryLogger(LoggerInfo, LoggerContext);
  775. }
  776. #ifndef WMI_MUTEX_FREE
  777. InterlockedDecrement(&LoggerContext->MutexCount);
  778. TraceDebug((1, "WmiFlushTrace: Release mutex %d %d\n",
  779. LoggerContext->LoggerId, LoggerContext->MutexCount));
  780. WmipReleaseMutex(&LoggerContext->LoggerMutex);
  781. #endif
  782. #if DBG
  783. RefCount =
  784. #endif
  785. WmipDereferenceLogger(LoggerId);
  786. TraceDebug((1, "WmiFlushTrace: %d %d->%d\n",
  787. LoggerId, RefCount+1, RefCount));
  788. return Status;
  789. }
  790. //
  791. // Trace Provider APIs
  792. //
  793. NTKERNELAPI
  794. NTSTATUS
  795. FASTCALL
  796. WmiGetClockType(
  797. IN TRACEHANDLE LoggerHandle,
  798. OUT WMI_CLOCK_TYPE *ClockType
  799. )
  800. /*++
  801. Routine Description:
  802. This is called by anyone internal to find the clock type
  803. that is in use with a logger specified by the LoggerHandle
  804. Arguments:
  805. LoggerHandle Handle to a tracelog session
  806. Return Value:
  807. The clock type
  808. --*/
  809. {
  810. ULONG LoggerId;
  811. #if DBG
  812. LONG RefCount;
  813. #endif
  814. PWMI_LOGGER_CONTEXT LoggerContext;
  815. LoggerId = WmiGetLoggerId(LoggerHandle);
  816. if (LoggerId < 1 || LoggerId >= MAXLOGGERS)
  817. return STATUS_INVALID_HANDLE;
  818. #if DBG
  819. RefCount =
  820. #endif
  821. WmipReferenceLogger(LoggerId);
  822. TraceDebug((4, "WmiGetClockType: %d %d->%d\n",
  823. LoggerId, RefCount-1, RefCount));
  824. LoggerContext = WmipGetLoggerContext( LoggerId );
  825. if (!WmipIsValidLogger(LoggerContext)) {
  826. #if DBG
  827. RefCount =
  828. #endif
  829. WmipDereferenceLogger(LoggerId);
  830. TraceDebug((4, "WmiGetClockType: Status=%X %d %d->%d\n",
  831. STATUS_WMI_INSTANCE_NOT_FOUND,
  832. LoggerId, RefCount+1, RefCount));
  833. return STATUS_WMI_INSTANCE_NOT_FOUND;
  834. }
  835. *ClockType = WMICT_SYSTEMTIME; // Default Clock Type
  836. if (LoggerContext->UsePerfClock & EVENT_TRACE_CLOCK_PERFCOUNTER) {
  837. *ClockType = WMICT_PERFCOUNTER;
  838. }
  839. else if (LoggerContext->UsePerfClock & EVENT_TRACE_CLOCK_CPUCYCLE) {
  840. *ClockType = WMICT_CPUCYCLE;
  841. }
  842. #if DBG
  843. RefCount =
  844. #endif
  845. WmipDereferenceLogger(LoggerId);
  846. return STATUS_SUCCESS;
  847. }
  848. NTKERNELAPI
  849. LONG64
  850. FASTCALL
  851. WmiGetClock(
  852. IN WMI_CLOCK_TYPE ClockType,
  853. IN PVOID Context
  854. )
  855. /*++
  856. Routine Description:
  857. This is called anyone internal to use a particular clock for
  858. sequencing events.
  859. Arguments:
  860. ClockType Should use WMICT_DEFAULT most of the time.
  861. Other clock types are for perf group.
  862. Context Only used for process/thread times
  863. Return Value:
  864. The clock value
  865. --*/
  866. {
  867. LARGE_INTEGER Clock;
  868. switch (ClockType) {
  869. case WMICT_DEFAULT :
  870. Clock.QuadPart = (*WmiGetCpuClock)();
  871. break;
  872. case WMICT_SYSTEMTIME:
  873. Clock.QuadPart = WmipGetSystemTime();
  874. break;
  875. case WMICT_PERFCOUNTER:
  876. Clock.QuadPart = WmipGetPerfCounter();
  877. break;
  878. case WMICT_PROCESS : // defaults to Process times for now
  879. {
  880. PEPROCESS Process = (PEPROCESS) Context;
  881. if (Process == NULL)
  882. Process = PsGetCurrentProcess();
  883. else {
  884. ObReferenceObject(Process);
  885. }
  886. Clock.HighPart = Process->Pcb.KernelTime;
  887. Clock.LowPart = Process->Pcb.UserTime;
  888. if (Context) {
  889. ObDereferenceObject(Process);
  890. }
  891. break;
  892. }
  893. case WMICT_THREAD : // defaults to Thread times for now
  894. {
  895. PETHREAD Thread = (PETHREAD) Context;
  896. if (Thread == NULL)
  897. Thread = PsGetCurrentThread();
  898. else {
  899. ObReferenceObject(Thread);
  900. }
  901. Clock.HighPart = Thread->Tcb.KernelTime;
  902. Clock.LowPart = Thread->Tcb.UserTime;
  903. if (Context) {
  904. ObDereferenceObject(Thread);
  905. }
  906. break;
  907. }
  908. default :
  909. KeQuerySystemTime(&Clock);
  910. }
  911. return ((LONG64) Clock.QuadPart);
  912. }
  913. NTSYSCALLAPI
  914. NTSTATUS
  915. NTAPI
  916. NtTraceEvent(
  917. IN HANDLE TraceHandle,
  918. IN ULONG Flags,
  919. IN ULONG FieldSize,
  920. IN PVOID Fields
  921. )
  922. /*++
  923. Routine Description:
  924. This routine is used by WMI data providers to trace events.
  925. It calls different tracing functions depending on the Flags.
  926. Arguments:
  927. TraceHandle LoggerId
  928. Flags Flags that indicate the type of the data being passed
  929. FieldSize Size of the Fields
  930. Fields Pointer to actual data (events)
  931. Return Value:
  932. STATUS_SUCCESS if the event trace is recorded successfully
  933. --*/
  934. {
  935. NTSTATUS Status;
  936. if (Flags & ETW_NT_FLAGS_TRACE_HEADER) {
  937. retry:
  938. Status = WmiTraceEvent((PWNODE_HEADER)Fields, KeGetPreviousMode());
  939. if (Status == STATUS_NO_MEMORY) {
  940. //
  941. // This logging is from user mode, try to allocate more buffer.
  942. //
  943. PWNODE_HEADER Wnode = (PWNODE_HEADER) Fields;
  944. ULONG LoggerId = WmiGetLoggerId(Wnode->HistoricalContext);
  945. PWMI_LOGGER_CONTEXT LoggerContext;
  946. if (LoggerId < 1 || LoggerId >= MAXLOGGERS) {
  947. Status = STATUS_INVALID_HANDLE;
  948. } else {
  949. WmipReferenceLogger(LoggerId);
  950. LoggerContext = WmipGetLoggerContext(LoggerId);
  951. //
  952. // Make sure collection is still on before allocate more
  953. // free buffers. This makes sure that logger thread
  954. // can free all allocated buffers.
  955. //
  956. if (WmipIsValidLogger(LoggerContext) &&
  957. LoggerContext->CollectionOn)
  958. {
  959. if (WmipAllocateFreeBuffers (LoggerContext, 1) == 1) {
  960. WmipDereferenceLogger(LoggerId);
  961. InterlockedDecrement((PLONG)&LoggerContext->EventsLost);
  962. goto retry;
  963. } else {
  964. Status = STATUS_NO_MEMORY;
  965. }
  966. }
  967. WmipDereferenceLogger(LoggerId);
  968. }
  969. }
  970. }
  971. else if (Flags & ETW_NT_FLAGS_TRACE_MESSAGE) {
  972. if (FieldSize < sizeof(MESSAGE_TRACE_USER)) {
  973. return (STATUS_UNSUCCESSFUL);
  974. }
  975. try {
  976. ProbeForRead(
  977. Fields,
  978. FieldSize,
  979. sizeof (UCHAR)
  980. );
  981. return (WmiTraceMessage((TRACEHANDLE)TraceHandle,
  982. ((PMESSAGE_TRACE_USER)Fields)->MessageFlags,
  983. &((PMESSAGE_TRACE_USER)Fields)->MessageGuid,
  984. ((PMESSAGE_TRACE_USER)Fields)->MessageHeader.Packet.MessageNumber,
  985. &((PMESSAGE_TRACE_USER)Fields)->Data,
  986. ((PMESSAGE_TRACE_USER)Fields)->DataSize,
  987. NULL,0));
  988. } except (EXCEPTION_EXECUTE_HANDLER) {
  989. TraceDebug((1, "NtTraceEvent: (ETW_NT_FLAGS_TRACE_MESSAGE) Status=EXCEPTION\n"));
  990. return GetExceptionCode();
  991. }
  992. }
  993. else {
  994. Status = STATUS_INVALID_PARAMETER;
  995. }
  996. return Status;
  997. }
  998. NTKERNELAPI
  999. NTSTATUS
  1000. FASTCALL
  1001. WmiTraceEvent(
  1002. IN PWNODE_HEADER Wnode,
  1003. IN KPROCESSOR_MODE RequestorMode
  1004. )
  1005. /*++
  1006. Routine Description:
  1007. This routine is used by WMI data providers to trace events.
  1008. It expects the user to pass in the handle to the logger.
  1009. Also, the user cannot ask to log something that is larger than
  1010. the buffer size (minus buffer header).
  1011. This routine works at IRQL <= DISPATCH_LEVEL
  1012. Arguments:
  1013. Wnode The WMI node header that will be overloaded
  1014. Return Value:
  1015. STATUS_SUCCESS if the event trace is recorded successfully
  1016. --*/
  1017. {
  1018. PEVENT_TRACE_HEADER TraceRecord = (PEVENT_TRACE_HEADER) Wnode;
  1019. ULONG WnodeSize, Size, LoggerId, Flags, HeaderSize;
  1020. PWMI_BUFFER_HEADER BufferResource = NULL;
  1021. NTSTATUS Status;
  1022. PETHREAD Thread;
  1023. PWMI_LOGGER_CONTEXT LoggerContext;
  1024. ULONG Marker;
  1025. MOF_FIELD MofFields[MAX_MOF_FIELDS];
  1026. long MofCount = 0;
  1027. LONG LoggerLocked = 0;
  1028. #if DBG
  1029. LONG RefCount;
  1030. #endif
  1031. if (TraceRecord == NULL)
  1032. return STATUS_SEVERITY_WARNING;
  1033. try {
  1034. HeaderSize = sizeof(WNODE_HEADER); // same size as EVENT_TRACE_HEADER
  1035. if (RequestorMode != KernelMode) {
  1036. ProbeForRead(
  1037. TraceRecord,
  1038. sizeof (EVENT_TRACE_HEADER),
  1039. sizeof (UCHAR)
  1040. );
  1041. Marker = Wnode->BufferSize; // check the first DWORD flags
  1042. Size = Marker;
  1043. if (Marker & TRACE_HEADER_FLAG) {
  1044. if ( ((Marker & TRACE_HEADER_ENUM_MASK) >> 16)
  1045. == TRACE_HEADER_TYPE_INSTANCE )
  1046. HeaderSize = sizeof(EVENT_INSTANCE_HEADER);
  1047. Size = TraceRecord->Size;
  1048. }
  1049. }
  1050. else {
  1051. Size = Wnode->BufferSize; // take the first DWORD flags
  1052. Marker = Size;
  1053. if (Marker & TRACE_HEADER_FLAG) {
  1054. if ( ((Marker & TRACE_HEADER_ENUM_MASK) >> 16)
  1055. == TRACE_HEADER_TYPE_INSTANCE )
  1056. HeaderSize = sizeof(EVENT_INSTANCE_HEADER);
  1057. Size = TraceRecord->Size;
  1058. }
  1059. }
  1060. WnodeSize = Size; // WnodeSize is for the contiguous block
  1061. // Size is for what we want in buffer
  1062. Flags = Wnode->Flags;
  1063. if (!(Flags & WNODE_FLAG_LOG_WNODE) &&
  1064. !(Flags & WNODE_FLAG_TRACED_GUID)) {
  1065. Status = STATUS_UNSUCCESSFUL;
  1066. goto ErrorReturn;
  1067. }
  1068. LoggerId = WmiGetLoggerId(Wnode->HistoricalContext);
  1069. if (LoggerId < 1 || LoggerId >= MAXLOGGERS) {
  1070. Status = STATUS_INVALID_HANDLE;
  1071. goto ErrorReturn;
  1072. }
  1073. LoggerLocked = WmipReferenceLogger(LoggerId);
  1074. #if DBG
  1075. RefCount = LoggerLocked;
  1076. #endif
  1077. TraceDebug((4, "WmiTraceEvent: %d %d->%d\n",
  1078. LoggerId, RefCount-1, RefCount));
  1079. LoggerContext = WmipGetLoggerContext(LoggerId);
  1080. if (!WmipIsValidLogger(LoggerContext)) {
  1081. #if DBG
  1082. RefCount =
  1083. #endif
  1084. WmipDereferenceLogger(LoggerId);
  1085. TraceDebug((4, "WmiTraceEvent: Status1=%X %d %d->%d\n",
  1086. STATUS_INVALID_HANDLE, LoggerId,
  1087. RefCount+1, RefCount));
  1088. Status = STATUS_INVALID_HANDLE;
  1089. goto ErrorReturn;
  1090. }
  1091. if ((RequestorMode == KernelMode) &&
  1092. (LoggerContext->LoggerMode & EVENT_TRACE_USE_PAGED_MEMORY)) {
  1093. return STATUS_UNSUCCESSFUL;
  1094. }
  1095. if (Flags & WNODE_FLAG_USE_MOF_PTR) {
  1096. //
  1097. // Need to compute the total size required, since the MOF fields
  1098. // in Wnode merely contains pointers
  1099. //
  1100. long i;
  1101. PCHAR Offset = ((PCHAR)Wnode) + HeaderSize;
  1102. ULONG MofSize, MaxSize;
  1103. MaxSize = LoggerContext->BufferSize - sizeof(WMI_BUFFER_HEADER);
  1104. MofSize = WnodeSize - HeaderSize;
  1105. // allow only the maximum
  1106. if (MofSize > (sizeof(MOF_FIELD) * MAX_MOF_FIELDS)) {
  1107. WmipDereferenceLogger(LoggerId);
  1108. return STATUS_ARRAY_BOUNDS_EXCEEDED;
  1109. }
  1110. if (MofSize > 0) { // Make sure we can read the rest
  1111. if (RequestorMode != KernelMode) {
  1112. ProbeForRead( Offset, MofSize, sizeof (UCHAR) );
  1113. }
  1114. RtlCopyMemory(MofFields, Offset, MofSize);
  1115. }
  1116. Size = HeaderSize;
  1117. MofCount = MofSize / sizeof(MOF_FIELD);
  1118. for (i=0; i<MofCount; i++) {
  1119. MofSize = MofFields[i].Length;
  1120. if (MofSize >= (MaxSize - Size)) { // check for overflow first
  1121. #if DBG
  1122. RefCount =
  1123. #endif
  1124. WmipDereferenceLogger(LoggerId);
  1125. TraceDebug((4, "WmiTraceEvent: Status2=%X %d %d->%d\n",
  1126. STATUS_BUFFER_OVERFLOW, LoggerId,
  1127. RefCount+1, RefCount));
  1128. Status = STATUS_BUFFER_OVERFLOW;
  1129. goto ErrorReturn;
  1130. }
  1131. Size += MofSize;
  1132. // if ( (Size > MaxSize) || (Size < MofSize) )
  1133. // return STATUS_BUFFER_OVERFLOW;
  1134. }
  1135. }
  1136. if ( (Size > LoggerContext->BufferSize - sizeof(WMI_BUFFER_HEADER)) ||
  1137. ( (Flags & WNODE_FLAG_TRACED_GUID) && (Size > 0xFFFF)) ) {
  1138. LoggerContext->EventsLost++;
  1139. #ifndef WMI_NON_BLOCKING
  1140. LoggerContext->ProcessorBuffers[KeGetCurrentProcessorNumber()]
  1141. ->EventsLost++;
  1142. #endif //WMI_NON_BLOCKING
  1143. #if DBG
  1144. RefCount =
  1145. #endif
  1146. WmipDereferenceLogger(LoggerId);
  1147. TraceDebug((4, "WmiTraceEvent: Status3=%X %d %d->%d\n",
  1148. STATUS_BUFFER_OVERFLOW, LoggerId,
  1149. RefCount+1, RefCount));
  1150. Status = STATUS_BUFFER_OVERFLOW;
  1151. goto ErrorReturn;
  1152. }
  1153. if ((LoggerContext->LoggerMode & EVENT_TRACE_FILE_MODE_CIRCULAR) &&
  1154. (LoggerContext->RequestFlag & REQUEST_FLAG_CIRCULAR_PERSIST)) {
  1155. if (! (Flags & WNODE_FLAG_PERSIST_EVENT) ) {
  1156. ULONG RequestFlag = LoggerContext->RequestFlag
  1157. & (~ ( REQUEST_FLAG_CIRCULAR_PERSIST
  1158. | REQUEST_FLAG_CIRCULAR_TRANSITION));
  1159. if (InterlockedCompareExchange(
  1160. (PLONG) &LoggerContext->RequestFlag,
  1161. RequestFlag | REQUEST_FLAG_CIRCULAR_TRANSITION,
  1162. RequestFlag | REQUEST_FLAG_CIRCULAR_PERSIST)) {
  1163. // All persistence events are fired in circular
  1164. // logfile, flush out all active buffers and flushlist
  1165. // buffers. Also mark the end of persistence event
  1166. // collection in circular logger.
  1167. //
  1168. // It is the provider's resposibility to ensure that
  1169. // no persist event fires after this point. If it did,
  1170. // that event may be overwritten during wrap around.
  1171. //
  1172. if (KeGetCurrentIrql() < DISPATCH_LEVEL) {
  1173. Status = WmipFlushLogger(LoggerContext, TRUE);
  1174. }
  1175. }
  1176. }
  1177. }
  1178. // So, now reserve some space in logger buffer and set that to TraceRecord
  1179. TraceRecord = (PEVENT_TRACE_HEADER)
  1180. WmipReserveTraceBuffer(
  1181. LoggerContext,
  1182. Size,
  1183. &BufferResource
  1184. );
  1185. if (TraceRecord == NULL) {
  1186. #if DBG
  1187. RefCount =
  1188. #endif
  1189. WmipDereferenceLogger(LoggerId);
  1190. TraceDebug((4, "WmiTraceEvent: Status4=%X %d %d->%d\n",
  1191. STATUS_NO_MEMORY, LoggerId,
  1192. RefCount+1, RefCount));
  1193. Status = STATUS_NO_MEMORY;
  1194. goto ErrorReturn;
  1195. }
  1196. if (Flags & WNODE_FLAG_USE_MOF_PTR) {
  1197. //
  1198. // Now we need to probe and copy all the MOF data fields
  1199. //
  1200. PVOID MofPtr;
  1201. ULONG MofLen;
  1202. long i;
  1203. PCHAR TraceOffset = (PCHAR) TraceRecord + HeaderSize;
  1204. if (RequestorMode != KernelMode) {
  1205. ProbeForRead(Wnode, HeaderSize, sizeof(UCHAR));
  1206. }
  1207. RtlCopyMemory(TraceRecord, Wnode, HeaderSize);
  1208. TraceRecord->Size = (USHORT)Size; // reset to Total Size
  1209. for (i=0; i<MofCount; i++) {
  1210. MofPtr = (PVOID) MofFields[i].DataPtr;
  1211. MofLen = MofFields[i].Length;
  1212. if (MofPtr == NULL || MofLen == 0)
  1213. continue;
  1214. if (RequestorMode != KernelMode) {
  1215. ProbeForRead(MofPtr, MofLen, sizeof(UCHAR));
  1216. }
  1217. RtlCopyMemory(TraceOffset, MofPtr, MofLen);
  1218. TraceOffset += MofLen;
  1219. }
  1220. }
  1221. else {
  1222. if (RequestorMode != KernelMode) {
  1223. ProbeForRead(Wnode, Size, sizeof(UCHAR));
  1224. }
  1225. RtlCopyMemory(TraceRecord, Wnode, Size);
  1226. }
  1227. if (Flags & WNODE_FLAG_USE_GUID_PTR) {
  1228. PVOID GuidPtr = (PVOID) ((PEVENT_TRACE_HEADER)Wnode)->GuidPtr;
  1229. if (RequestorMode != KernelMode) {
  1230. ProbeForReadSmallStructure(GuidPtr, sizeof(GUID), sizeof(UCHAR));
  1231. }
  1232. RtlCopyMemory(&TraceRecord->Guid, GuidPtr, sizeof(GUID));
  1233. }
  1234. }
  1235. except (EXCEPTION_EXECUTE_HANDLER) {
  1236. if (BufferResource != NULL) {
  1237. WmipReleaseTraceBuffer ( BufferResource, LoggerContext );
  1238. }
  1239. else {
  1240. if (LoggerLocked) {
  1241. #if DBG
  1242. RefCount =
  1243. #endif
  1244. WmipDereferenceLogger(LoggerId);
  1245. }
  1246. }
  1247. TraceDebug((4, "WmiTraceEvent: Status5=EXCEPTION %d %d->%d\n",
  1248. LoggerId, RefCount+1, RefCount));
  1249. return GetExceptionCode();
  1250. }
  1251. //
  1252. // By now, we have reserved space in the trace buffer
  1253. //
  1254. if (Marker & TRACE_HEADER_FLAG) {
  1255. if (! (WNODE_FLAG_USE_TIMESTAMP & TraceRecord->Flags) ) {
  1256. TraceRecord->TimeStamp.QuadPart = (*LoggerContext->GetCpuClock)();
  1257. }
  1258. Thread = PsGetCurrentThread();
  1259. if (Thread != NULL) {
  1260. TraceRecord->KernelTime = Thread->Tcb.KernelTime;
  1261. TraceRecord->UserTime = Thread->Tcb.UserTime;
  1262. TraceRecord->ThreadId = HandleToUlong(Thread->Cid.UniqueThread);
  1263. TraceRecord->ProcessId = HandleToUlong(Thread->Cid.UniqueProcess);
  1264. }
  1265. }
  1266. WmipReleaseTraceBuffer( BufferResource, LoggerContext );
  1267. TraceDebug((4, "WmiTraceEvent: %d %d->%d\n",
  1268. LoggerId, RefCount+1, RefCount));
  1269. return STATUS_SUCCESS;
  1270. ErrorReturn:
  1271. return Status;
  1272. }
  1273. NTKERNELAPI
  1274. NTSTATUS
  1275. WmiTraceKernelEvent(
  1276. IN ULONG GroupType, // Group/type code for kernel event
  1277. IN PVOID EventInfo, // Event data as defined in MOF
  1278. IN ULONG EventInfoLen, // Length of the event data
  1279. IN PETHREAD Thread ) // use NULL for current caller thread
  1280. /*++
  1281. Routine Description:
  1282. This routine is used by trace kernel events only. These events can
  1283. be charged to the given thread instead of the running thread. Because
  1284. it can be called by I/O events at DPC level, this routine cannot be
  1285. pageable when tracing is on.
  1286. This routine works at IRQL <= DISPATCH_LEVEL
  1287. Arguments:
  1288. GroupType a ULONG key to indicate the action to be taken
  1289. EventInfo a pointer to contiguous memory containing information
  1290. to be attached to event trace
  1291. EventInfoLen length of EventInfo
  1292. Thread Pointer to thread where event is to be charged.
  1293. Currently used by disk IO and thread events.
  1294. Return Value:
  1295. The status of performing the action requested
  1296. --*/
  1297. {
  1298. PSYSTEM_TRACE_HEADER Header;
  1299. ULONG Size;
  1300. PWMI_BUFFER_HEADER BufferResource = NULL;
  1301. PWMI_LOGGER_CONTEXT LoggerContext = WmipLoggerContext[WmipKernelLogger];
  1302. #if DBG
  1303. LONG RefCount;
  1304. #endif
  1305. #if DBG
  1306. RefCount =
  1307. #endif
  1308. WmipReferenceLogger(WmipKernelLogger);
  1309. TraceDebug((4, "WmiTraceKernelEvent: 0 %d->%d\n", RefCount-1, RefCount));
  1310. // Make sure that kernel logger is enabled first
  1311. if (!WmipIsValidLogger(LoggerContext)) {
  1312. WmipDereferenceLogger(WmipKernelLogger);
  1313. return STATUS_ALREADY_DISCONNECTED;
  1314. }
  1315. // Compute total size of event trace record
  1316. Size = sizeof(SYSTEM_TRACE_HEADER) + EventInfoLen;
  1317. if (Size > LoggerContext->BufferSize - sizeof(WMI_BUFFER_HEADER)) {
  1318. LoggerContext->EventsLost++;
  1319. #ifndef WMI_NON_BLOCKING
  1320. LoggerContext->ProcessorBuffers[KeGetCurrentProcessorNumber()]
  1321. ->EventsLost++;
  1322. #endif //WMI_NON_BLOCKING
  1323. #if DBG
  1324. RefCount =
  1325. #endif
  1326. WmipDereferenceLogger(WmipKernelLogger);
  1327. TraceDebug((4, "WmiTraceKernelEvent: Status1=%X 0 %d->%d\n",
  1328. STATUS_BUFFER_OVERFLOW, RefCount+1, RefCount));
  1329. return STATUS_BUFFER_OVERFLOW;
  1330. }
  1331. // NOTE: we do not check for size here for reduce overhead, and because
  1332. // we trust ourselves to use WmiTraceLongEvent for large event traces
  1333. Header = (PSYSTEM_TRACE_HEADER)
  1334. WmipReserveTraceBuffer(
  1335. LoggerContext,
  1336. Size,
  1337. &BufferResource
  1338. );
  1339. if (Header == NULL) {
  1340. #if DBG
  1341. RefCount =
  1342. #endif
  1343. WmipDereferenceLogger(WmipKernelLogger);
  1344. TraceDebug((4, "WmiTraceKernelEvent: Status1=%X 0 %d->%d\n",
  1345. STATUS_NO_MEMORY, RefCount+1, RefCount));
  1346. return STATUS_NO_MEMORY;
  1347. }
  1348. // Get the current system time as time stamp for trace record
  1349. PerfTimeStamp(Header->SystemTime);
  1350. if (Thread == NULL) {
  1351. Thread = PsGetCurrentThread();
  1352. }
  1353. //
  1354. // Now copy the necessary information into the buffer
  1355. //
  1356. Header->Marker = SYSTEM_TRACE_MARKER;
  1357. Header->ThreadId = HandleToUlong(Thread->Cid.UniqueThread);
  1358. Header->ProcessId = HandleToUlong(Thread->Cid.UniqueProcess);
  1359. Header->KernelTime = Thread->Tcb.KernelTime;
  1360. Header->UserTime = Thread->Tcb.UserTime;
  1361. Header->Header = (GroupType << 16) + Size;
  1362. if (EventInfoLen > 0) {
  1363. RtlCopyMemory (
  1364. (UCHAR*) Header + sizeof(SYSTEM_TRACE_HEADER),
  1365. EventInfo, EventInfoLen);
  1366. }
  1367. #if DBG
  1368. RefCount = WmipRefCount[LoggerContext->LoggerId] - 1;
  1369. #endif
  1370. WmipReleaseTraceBuffer( BufferResource, LoggerContext );
  1371. TraceDebug((4, "WmiTraceKernelEvent: 0 %d->%d\n",
  1372. RefCount+1, RefCount));
  1373. return STATUS_SUCCESS;
  1374. }
  1375. #if 0
  1376. NTKERNELAPI
  1377. NTSTATUS
  1378. WmiTraceLongEvent(
  1379. IN ULONG GroupType,
  1380. IN PMOF_FIELD EventFields,
  1381. IN ULONG FieldCount,
  1382. IN PETHREAD Thread
  1383. )
  1384. /*++
  1385. Routine Description:
  1386. This routine is used by trace kernel events with long traces only.
  1387. These events can be charged to the given thread instead of the running
  1388. thread. Because it can be called by I/O events at DPC level, this routine
  1389. cannot be pageable when tracing is on.
  1390. This routine is used to trace filenames.
  1391. This routine works at IRQL <= DISPATCH_LEVEL
  1392. Arguments:
  1393. GroupType a ULONG key to indicate the action to be taken
  1394. EventFields an array of structures describing each field
  1395. to be attached to event trace
  1396. FieldCount number of array entries in EventFields
  1397. Thread Pointer to thread where event is to be charged.
  1398. Return Value:
  1399. The status of performing the action requested
  1400. --*/
  1401. {
  1402. PSYSTEM_TRACE_HEADER Header;
  1403. ULONG Size, i, maxLength;
  1404. PWMI_BUFFER_HEADER BufferResource;
  1405. NTSTATUS Status;
  1406. PWMI_LOGGER_CONTEXT LoggerContext = WmipLoggerContext[WmipKernelLogger];
  1407. char *auxInfo;
  1408. #if DBG
  1409. LONG RefCount;
  1410. #endif
  1411. // Make sure that kernel logger is enabled first
  1412. if (LoggerContext == NULL)
  1413. return STATUS_ALREADY_DISCONNECTED;
  1414. #if DBG
  1415. RefCount =
  1416. #endif
  1417. WmipReferenceLogger(WmipKernelLogger);
  1418. /* Compute total size of event trace record */
  1419. Size = sizeof(SYSTEM_TRACE_HEADER);
  1420. maxLength = LoggerContext->BufferSize / 2;
  1421. for (i=0; i<FieldCount; i++) {
  1422. // if (EventFields[i].Length > maxLength) {
  1423. // Size += maxLength / 2;
  1424. // break;
  1425. // }
  1426. Size += EventFields[i].Length;
  1427. }
  1428. if (Size > LoggerContext->BufferSize - sizeof(WMI_BUFFER_HEADER)) {
  1429. LoggerContext->EventsLost++;
  1430. LoggerContext->ProcessorBuffers[KeGetCurrentProcessorNumber()]
  1431. ->EventsLost++;
  1432. #if DBG
  1433. RefCount =
  1434. #endif
  1435. WmipDereferenceLogger(WmipKernelLogger);
  1436. return STATUS_BUFFER_OVERFLOW;
  1437. }
  1438. Header = (PSYSTEM_TRACE_HEADER)
  1439. WmipReserveTraceBuffer(
  1440. LoggerContext,
  1441. Size,
  1442. &BufferResource
  1443. );
  1444. if (Header == NULL) {
  1445. #if DBG
  1446. RefCount =
  1447. #endif
  1448. WmipDereferenceLogger(WmipKernelLogger);
  1449. return STATUS_NO_MEMORY;
  1450. }
  1451. // Get the current system time as time stamp for trace record
  1452. Header->SystemTime.QuadPart = (*LoggerContext->GetCpuClock)();
  1453. if (Thread == NULL) {
  1454. Thread = PsGetCurrentThread();
  1455. }
  1456. //
  1457. // Now copy the necessary information into the buffer
  1458. //
  1459. Header->Marker = SYSTEM_TRACE_MARKER;
  1460. Header->ThreadId = HandleToUlong(Thread->Cid.UniqueThread);
  1461. Header->ProcessId = HandleToUlong(Thread->Cid.UniqueProcess);
  1462. Header->KernelTime = Thread->Tcb.KernelTime;
  1463. Header->UserTime = Thread->Tcb.UserTime;
  1464. Header->Header = (GroupType << 16) + Size;
  1465. auxInfo = (char *) Header + sizeof(SYSTEM_TRACE_HEADER);
  1466. for (i=0; i<FieldCount; i++) {
  1467. Size = EventFields[i].Length;
  1468. // For NT5, do not support large events
  1469. /* if (Size > maxLength) {
  1470. RtlCopyMemory(auxInfo, (PVOID) EventFields[i].DataPtr, maxLength/2);
  1471. EventFields[i].DataPtr = (ULONGLONG)
  1472. ((char*) EventFields[i].DataPtr +
  1473. (maxLength / 2));
  1474. EventFields[i].Length -= maxLength / 2;
  1475. GroupType &= 0xFFFFFF00; // turn off event to info
  1476. WmiTraceLongEvent(GroupType,
  1477. &EventFields[i], FieldCount + 1 - i, Thread);
  1478. break;
  1479. }
  1480. */
  1481. RtlCopyMemory ( auxInfo, (PVOID) EventFields[i].DataPtr, Size);
  1482. auxInfo += Size;
  1483. }
  1484. WmipReleaseTraceBuffer( BufferResource, LoggerContext );
  1485. return STATUS_SUCCESS;
  1486. }
  1487. #endif
  1488. NTKERNELAPI
  1489. NTSTATUS
  1490. FASTCALL
  1491. WmiTraceFastEvent(
  1492. IN PWNODE_HEADER Wnode
  1493. )
  1494. /*++
  1495. Routine Description:
  1496. This routine is used by short events using abbreviated header.
  1497. This routine should work at any IRQL.
  1498. Arguments:
  1499. Wnode Header of event to record
  1500. Return Value:
  1501. The status of performing the action requested
  1502. --*/
  1503. {
  1504. ULONG Size;
  1505. PTIMED_TRACE_HEADER Buffer;
  1506. PTIMED_TRACE_HEADER Header = (PTIMED_TRACE_HEADER) Wnode;
  1507. PWMI_BUFFER_HEADER BufferResource;
  1508. ULONG LoggerId = (ULONG) Header->LoggerId; // get the lower ULONG!!
  1509. PULONG Marker;
  1510. PWMI_LOGGER_CONTEXT LoggerContext;
  1511. #if DBG
  1512. LONG RefCount;
  1513. #endif
  1514. Marker = (PULONG) Wnode;
  1515. if ((LoggerId == WmipKernelLogger) || (LoggerId >= MAXLOGGERS))
  1516. return STATUS_INVALID_HANDLE;
  1517. if ((*Marker & 0xF0000000) == TRACE_HEADER_ULONG32_TIME) {
  1518. Size = Header->Size;
  1519. if (Size == 0)
  1520. return STATUS_INVALID_BUFFER_SIZE;
  1521. #if DBG
  1522. RefCount =
  1523. #endif
  1524. WmipReferenceLogger(LoggerId);
  1525. LoggerContext = WmipGetLoggerContext(LoggerId);
  1526. if (!WmipIsValidLogger(LoggerContext)) {
  1527. #if DBG
  1528. RefCount =
  1529. #endif
  1530. WmipDereferenceLogger(LoggerId);
  1531. return STATUS_INVALID_HANDLE;
  1532. }
  1533. Buffer = WmipReserveTraceBuffer(LoggerContext, Size, &BufferResource);
  1534. if (Buffer == NULL) {
  1535. #if DBG
  1536. RefCount =
  1537. #endif
  1538. WmipDereferenceLogger(LoggerId);
  1539. return STATUS_NO_MEMORY;
  1540. }
  1541. (* (PULONG) Buffer) = *Marker;
  1542. Buffer->EventId = Header->EventId;
  1543. Buffer->TimeStamp.QuadPart = (*LoggerContext->GetCpuClock)();
  1544. RtlCopyMemory(Buffer+1, Header+1, Size-(sizeof(TIMED_TRACE_HEADER)));
  1545. WmipReleaseTraceBuffer(BufferResource, LoggerContext);
  1546. return STATUS_SUCCESS;
  1547. }
  1548. TraceDebug((4, "WmiTraceFastEvent: Invalid header %X\n", *Marker));
  1549. return STATUS_INVALID_PARAMETER;
  1550. }
  1551. NTKERNELAPI
  1552. NTSTATUS
  1553. WmiTraceMessage(
  1554. IN TRACEHANDLE LoggerHandle,
  1555. IN ULONG MessageFlags,
  1556. IN LPGUID MessageGuid,
  1557. IN USHORT MessageNumber,
  1558. ...
  1559. )
  1560. /*++
  1561. Routine Description:
  1562. This routine is used by WMI data providers to trace Messages.
  1563. It expects the user to pass in the handle to the logger.
  1564. Also, the user cannot ask to log something that is larger than
  1565. the buffer size (minus buffer header).
  1566. Arguments:
  1567. // IN TRACEHANDLE LoggerHandle - LoggerHandle obtained earlier
  1568. // IN ULONG MessageFlags, - Flags which both control what standard values are logged and
  1569. // the lower 16-bits are also included in the message header
  1570. // to control decoding
  1571. // IN PGUID MessageGuid, - Pointer to the message GUID of this set of messages or if
  1572. // TRACE_COMPONENTID is set the actual compnent ID
  1573. // IN USHORT MessageNumber, - The type of message being logged, associates it with the
  1574. // appropriate format string
  1575. // ... - List of arguments to be processed with the format string
  1576. // these are stored as pairs of
  1577. // PVOID - ptr to argument
  1578. // ULONG - size of argument
  1579. // and terminated by a pointer to NULL, length of zero pair.
  1580. Return Value:
  1581. STATUS_SUCCESS if the event trace is recorded successfully
  1582. NOTE:
  1583. this routine is called from WmiTraceUserMessage path via an IOCTL so the probes and
  1584. try/excepts have to be carefully managed
  1585. --*/
  1586. {
  1587. va_list MessageArgList ;
  1588. va_start(MessageArgList,MessageNumber);
  1589. return (WmiTraceMessageVa(LoggerHandle,
  1590. MessageFlags,
  1591. MessageGuid,
  1592. MessageNumber,
  1593. MessageArgList));
  1594. }
  1595. NTSTATUS
  1596. WmiTraceMessageVa(
  1597. IN TRACEHANDLE LoggerHandle,
  1598. IN ULONG MessageFlags,
  1599. IN LPGUID MessageGuid,
  1600. IN USHORT MessageNumber,
  1601. va_list MessageArgList
  1602. )
  1603. /*++ WmiTraceMessageVa
  1604. The VA version of WmiTraceMessage
  1605. NOTE:
  1606. this routine is called from WmiTraceUserMessage path via an IOCTL so the probes and
  1607. try/excepts have to be carefully managed
  1608. --*/
  1609. {
  1610. SSIZE_T dataBytes;
  1611. PMESSAGE_TRACE_HEADER Header;
  1612. PUCHAR pMessageData ;
  1613. PWMI_BUFFER_HEADER BufferResource = NULL ;
  1614. USHORT size ;
  1615. ULONG LoggerId = (ULONG)-1 ; // initialise so we don't unlock it if not set
  1616. ULONG SequenceNumber ;
  1617. PWMI_LOGGER_CONTEXT LoggerContext;
  1618. #if DBG
  1619. LONG RefCount;
  1620. #endif
  1621. // Set the LoggerId up here, and lock it.
  1622. // if we AV in the WmiUserTraceMessagePath we will
  1623. // be caught by the try/except in that routine
  1624. LoggerId = WmiGetLoggerId(LoggerHandle);
  1625. if (LoggerId < 1 || LoggerId >= MAXLOGGERS)
  1626. return STATUS_INVALID_HANDLE;
  1627. #if DBG
  1628. RefCount =
  1629. #endif
  1630. WmipReferenceLogger(LoggerId);
  1631. TraceDebug((4, "WmiTraceMessage: %d %d->%d\n",
  1632. LoggerId, RefCount-1, RefCount));
  1633. try {
  1634. //
  1635. // Determine the number bytes to follow header
  1636. //
  1637. dataBytes = 0;
  1638. { // Allocation Block
  1639. va_list ap;
  1640. PCHAR source;
  1641. ap = MessageArgList ;
  1642. while ((source = va_arg (ap, PVOID)) != NULL) {
  1643. SSIZE_T elemBytes;
  1644. if ((elemBytes = va_arg (ap, SSIZE_T)) > 0) {
  1645. dataBytes += elemBytes;
  1646. }
  1647. }
  1648. } // end of allocation block
  1649. // Figure the size of the message including the header
  1650. size = (MessageFlags&TRACE_MESSAGE_SEQUENCE ? sizeof(ULONG):0) +
  1651. (MessageFlags&TRACE_MESSAGE_GUID ? sizeof(GUID):0) +
  1652. (MessageFlags&TRACE_MESSAGE_COMPONENTID ? sizeof(ULONG):0) +
  1653. (MessageFlags&(TRACE_MESSAGE_TIMESTAMP | TRACE_MESSAGE_PERFORMANCE_TIMESTAMP) ? sizeof(LARGE_INTEGER):0) +
  1654. (MessageFlags&TRACE_MESSAGE_SYSTEMINFO ? 2 * sizeof(ULONG):0) +
  1655. sizeof (MESSAGE_TRACE_HEADER) +
  1656. (USHORT)dataBytes ;
  1657. //
  1658. // Allocate Space in the Trace Buffer
  1659. //
  1660. // NOTE: we do not check for size here for reduce overhead, and because
  1661. // we trust ourselves to use WmiTraceLongEvent for large event traces (???)
  1662. LoggerContext = WmipGetLoggerContext(LoggerId);
  1663. if (!WmipIsValidLogger(LoggerContext)) {
  1664. #if DBG
  1665. RefCount =
  1666. #endif
  1667. WmipDereferenceLogger(LoggerId);
  1668. TraceDebug((4, "WmiTraceMessage: Status1=%X %d %d->%d\n",
  1669. STATUS_INVALID_HANDLE, LoggerId,
  1670. RefCount+1, RefCount));
  1671. return STATUS_INVALID_HANDLE;
  1672. }
  1673. if ((LoggerContext->RequestFlag & REQUEST_FLAG_CIRCULAR_PERSIST) &&
  1674. (LoggerContext->LoggerMode & EVENT_TRACE_FILE_MODE_CIRCULAR)) {
  1675. // Unset REQUEST_FLAG_CIRCULAR_PERSIST flag
  1676. // Since persistent events will never be mixed with TraceMessage(),
  1677. // we'll just unset it once and for all without flushing.
  1678. LoggerContext->RequestFlag &= (~( REQUEST_FLAG_CIRCULAR_PERSIST
  1679. | REQUEST_FLAG_CIRCULAR_TRANSITION));
  1680. }
  1681. if ((KeGetPreviousMode() == KernelMode) &&
  1682. (LoggerContext->LoggerMode & EVENT_TRACE_USE_PAGED_MEMORY)) {
  1683. return STATUS_UNSUCCESSFUL;
  1684. }
  1685. if ((Header = (PMESSAGE_TRACE_HEADER)WmipReserveTraceBuffer(LoggerContext,size,&BufferResource)) == NULL) {
  1686. #if DBG
  1687. RefCount =
  1688. #endif
  1689. WmipDereferenceLogger(LoggerId);
  1690. TraceDebug((4, "WmiTraceMessage: %d %d->%d\n",
  1691. LoggerId, RefCount+1, RefCount));
  1692. return STATUS_NO_MEMORY;
  1693. }
  1694. //
  1695. // Sequence Number is returned in the Marker field of the buffer
  1696. //
  1697. SequenceNumber = Header->Marker ;
  1698. //
  1699. // Now copy the necessary information into the buffer
  1700. //
  1701. Header->Marker = TRACE_MESSAGE | TRACE_HEADER_FLAG ;
  1702. //
  1703. // Fill in Header.
  1704. //
  1705. Header->Size = size ;
  1706. Header->Packet.OptionFlags = ((USHORT)MessageFlags &
  1707. (TRACE_MESSAGE_SEQUENCE |
  1708. TRACE_MESSAGE_GUID |
  1709. TRACE_MESSAGE_COMPONENTID |
  1710. TRACE_MESSAGE_TIMESTAMP |
  1711. TRACE_MESSAGE_PERFORMANCE_TIMESTAMP |
  1712. TRACE_MESSAGE_SYSTEMINFO)) &
  1713. TRACE_MESSAGE_FLAG_MASK ;
  1714. // Message Number
  1715. Header->Packet.MessageNumber = MessageNumber ;
  1716. //
  1717. // Now add in the header options we counted.
  1718. //
  1719. pMessageData = &(((PMESSAGE_TRACE)Header)->Data);
  1720. //
  1721. // Note that the order in which these are added is critical New entries must
  1722. // be added at the end!
  1723. //
  1724. // [First Entry] Sequence Number
  1725. if (MessageFlags&TRACE_MESSAGE_SEQUENCE) {
  1726. *((PULONG)pMessageData) = SequenceNumber;
  1727. pMessageData += sizeof(ULONG) ;
  1728. }
  1729. // [Second Entry] GUID ? or CompnentID ?
  1730. if (MessageFlags&TRACE_MESSAGE_COMPONENTID) {
  1731. *((PULONG)pMessageData) = *((PULONG) MessageGuid);
  1732. pMessageData += sizeof(ULONG) ;
  1733. } else if (MessageFlags&TRACE_MESSAGE_GUID) { // Can't have both
  1734. *((LPGUID)pMessageData) = *MessageGuid;
  1735. pMessageData += sizeof(GUID) ;
  1736. }
  1737. // [Third Entry] Timestamp?
  1738. if (MessageFlags&TRACE_MESSAGE_TIMESTAMP) {
  1739. if (MessageFlags&TRACE_MESSAGE_PERFORMANCE_TIMESTAMP) {
  1740. *((PLARGE_INTEGER)pMessageData) = KeQueryPerformanceCounter(NULL);
  1741. } else {
  1742. KeQuerySystemTime((PLARGE_INTEGER)pMessageData);
  1743. }
  1744. pMessageData += sizeof(LARGE_INTEGER);
  1745. }
  1746. // [Fourth Entry] System Information?
  1747. // Note that some of this may NOT be valid depending on the current processing level
  1748. // however we assume that the post-processing may still find it useful
  1749. if (MessageFlags&TRACE_MESSAGE_SYSTEMINFO) {
  1750. PCLIENT_ID Cid; // avoid additional function calls
  1751. Cid = &(PsGetCurrentThread()->Cid);
  1752. // Executive Handles may be truncated
  1753. *((PULONG)pMessageData) = HandleToUlong(Cid->UniqueThread);
  1754. pMessageData += sizeof(ULONG) ;
  1755. *((PULONG)pMessageData) = HandleToUlong(Cid->UniqueProcess);
  1756. pMessageData += sizeof(ULONG) ;
  1757. }
  1758. //
  1759. // Add New Header Entries immediately before this comment!
  1760. //
  1761. //
  1762. // Now Copy in the Data.
  1763. //
  1764. { // Allocation Block
  1765. va_list ap;
  1766. PUCHAR source;
  1767. ap = MessageArgList ;
  1768. while ((source = va_arg (ap, PVOID)) != NULL) {
  1769. SSIZE_T elemBytes, copiedBytes = 0 ;
  1770. if ((elemBytes = va_arg (ap, SSIZE_T)) > 0 ) {
  1771. if (dataBytes < copiedBytes + elemBytes) { // defend against bytes having changed
  1772. TraceDebug((1, "WmiTraceMessage: Invalid message - argument length changed"));
  1773. break; // So we don't overrun
  1774. }
  1775. RtlCopyMemory (pMessageData, source, elemBytes);
  1776. copiedBytes += elemBytes ;
  1777. pMessageData += elemBytes;
  1778. }
  1779. }
  1780. } // Allocation Block
  1781. } except (EXCEPTION_EXECUTE_HANDLER) {
  1782. if (BufferResource != NULL) {
  1783. WmipReleaseTraceBuffer ( BufferResource, LoggerContext ); // also unlocks the logger
  1784. } else {
  1785. #if DBG
  1786. RefCount =
  1787. #endif
  1788. WmipDereferenceLogger(LoggerId);
  1789. }
  1790. TraceDebug((4, "WmiTraceMessage: Status6=EXCEPTION %d %d->%d\n",
  1791. LoggerId, RefCount+1, RefCount));
  1792. return GetExceptionCode();
  1793. }
  1794. //
  1795. // Buffer Complete, Release
  1796. //
  1797. WmipReleaseTraceBuffer( BufferResource, LoggerContext ); // Also unlocks the logger
  1798. TraceDebug((4, "WmiTraceMessage: %d %d->%d\n",
  1799. LoggerId, RefCount+1, RefCount));
  1800. //
  1801. // Return Success
  1802. //
  1803. return (STATUS_SUCCESS);
  1804. }
  1805. NTKERNELAPI
  1806. NTSTATUS
  1807. FASTCALL
  1808. WmiTraceUserMessage(
  1809. IN PMESSAGE_TRACE_USER pMessage,
  1810. IN ULONG MessageSize
  1811. )
  1812. /*++
  1813. Routine Description:
  1814. This routine is used by trace User messages only. it is called via an IOCTL
  1815. on the WMI Device.
  1816. Arguments:
  1817. pMessage a pointer to a Marshalled Message.
  1818. MessageSize size of that message.
  1819. Return Value:
  1820. The status of performing the action requested
  1821. --*/
  1822. {
  1823. if (MessageSize < sizeof(MESSAGE_TRACE_USER)) {
  1824. return (STATUS_UNSUCCESSFUL);
  1825. }
  1826. try {
  1827. ProbeForRead(
  1828. pMessage,
  1829. MessageSize,
  1830. sizeof (UCHAR)
  1831. );
  1832. return (WmiTraceMessage(pMessage->LoggerHandle,
  1833. pMessage->MessageFlags,
  1834. &pMessage->MessageGuid,
  1835. pMessage->MessageHeader.Packet.MessageNumber,
  1836. &pMessage->Data,pMessage->DataSize,
  1837. NULL,0));
  1838. } except (EXCEPTION_EXECUTE_HANDLER) {
  1839. TraceDebug((1, "WmiTraceUserMessage: Status=EXCEPTION\n"));
  1840. return GetExceptionCode();
  1841. }
  1842. }
  1843. NTKERNELAPI
  1844. NTSTATUS
  1845. WmiSetMark(
  1846. IN PWMI_SET_MARK_INFORMATION MarkInfo,
  1847. IN ULONG InBufferLen
  1848. )
  1849. /*++
  1850. Routine Description:
  1851. This routine sets a mark in the kernel logger.
  1852. Arguments:
  1853. MarkInfo - a pointer to a WMI_SET_MARK_INFORMATION strcture.
  1854. InBufferLen - Buffer Size.
  1855. Return Value:
  1856. status
  1857. --*/
  1858. {
  1859. NTSTATUS Status;
  1860. PERFINFO_HOOK_HANDLE Hook;
  1861. ULONG TotalBytes;
  1862. ULONG CopyBytes;
  1863. USHORT HookId;
  1864. if (PERFINFO_IS_ANY_GROUP_ON()) {
  1865. if (MarkInfo->Flag & WMI_SET_MARK_WITH_FLUSH) {
  1866. if (PERFINFO_IS_GROUP_ON(PERF_FOOTPRINT)) {
  1867. MmEmptyAllWorkingSets();
  1868. Status = MmPerfSnapShotValidPhysicalMemory();
  1869. }
  1870. }
  1871. HookId = PERFINFO_LOG_TYPE_MARK;
  1872. CopyBytes = InBufferLen - FIELD_OFFSET(WMI_SET_MARK_INFORMATION, Mark);
  1873. TotalBytes = CopyBytes + sizeof(WCHAR);
  1874. Status = PerfInfoReserveBytes(&Hook, HookId, TotalBytes);
  1875. if (NT_SUCCESS(Status)){
  1876. PWCHAR Mark = PERFINFO_HOOK_HANDLE_TO_DATA(Hook, PWCHAR);
  1877. RtlCopyMemory(Mark, &MarkInfo->Mark[0], CopyBytes);
  1878. Mark[CopyBytes / sizeof(WCHAR)] = UNICODE_NULL;
  1879. PERF_FINISH_HOOK(Hook);
  1880. }
  1881. } else {
  1882. Status = STATUS_WMI_SET_FAILURE;
  1883. }
  1884. return Status;
  1885. }
  1886. NTKERNELAPI
  1887. NTSTATUS
  1888. WmiSetTraceBufferCallback(
  1889. IN TRACEHANDLE TraceHandle,
  1890. IN WMI_TRACE_BUFFER_CALLBACK Callback,
  1891. IN PVOID Context
  1892. )
  1893. {
  1894. ULONG LoggerId;
  1895. #if DBG
  1896. LONG RefCount;
  1897. #endif
  1898. PWMI_LOGGER_CONTEXT LoggerContext;
  1899. PAGED_CODE();
  1900. if (TraceHandle == (TRACEHANDLE) 0) {
  1901. WmipGlobalBufferCallback = Callback;
  1902. return STATUS_SUCCESS;
  1903. }
  1904. LoggerId = WmiGetLoggerId(TraceHandle);
  1905. if (LoggerId == KERNEL_LOGGER_ID) {
  1906. LoggerId = WmipKernelLogger;
  1907. }
  1908. else if (LoggerId < 1 || LoggerId >= MAXLOGGERS)
  1909. return STATUS_INVALID_HANDLE;
  1910. #if DBG
  1911. RefCount =
  1912. #endif
  1913. WmipReferenceLogger(LoggerId);
  1914. TraceDebug((4, "WmiSetTraceBufferCallback: %d %d->%d\n",
  1915. LoggerId, RefCount-1, RefCount));
  1916. LoggerContext = WmipGetLoggerContext( LoggerId );
  1917. if (!WmipIsValidLogger(LoggerContext)) {
  1918. #if DBG
  1919. RefCount =
  1920. #endif
  1921. WmipDereferenceLogger(LoggerId);
  1922. TraceDebug((4, "WmiSetTraceBufferCallback: Status=%X %d %d->%d\n",
  1923. STATUS_WMI_INSTANCE_NOT_FOUND,
  1924. LoggerId, RefCount+1, RefCount));
  1925. return STATUS_WMI_INSTANCE_NOT_FOUND;
  1926. }
  1927. LoggerContext->BufferCallback = Callback;
  1928. LoggerContext->CallbackContext = Context;
  1929. return STATUS_SUCCESS;
  1930. }
  1931. NTKERNELAPI
  1932. NTSTATUS
  1933. WmiQueryTraceInformation(
  1934. IN TRACE_INFORMATION_CLASS TraceInformationClass,
  1935. OUT PVOID TraceInformation,
  1936. IN ULONG TraceInformationLength,
  1937. OUT PULONG RequiredLength OPTIONAL,
  1938. IN PVOID Buffer OPTIONAL
  1939. )
  1940. {
  1941. ULONG LoggerId;
  1942. ULONG EnableFlags;
  1943. ULONG EnableLevel;
  1944. ULONG LoggersLength;
  1945. TRACEHANDLE TraceHandle;
  1946. TRACEHANDLE AllHandles[MAXLOGGERS];
  1947. NTSTATUS Status = STATUS_SUCCESS;
  1948. PWNODE_HEADER Wnode = (PWNODE_HEADER) Buffer; // For most classes, but not all
  1949. PAGED_CODE();
  1950. try {
  1951. if (ARGUMENT_PRESENT(RequiredLength)) {
  1952. *RequiredLength = 0;
  1953. }
  1954. switch (TraceInformationClass) {
  1955. case TraceIdClass:
  1956. if (TraceInformationLength != sizeof( ULONG )) {
  1957. return STATUS_INFO_LENGTH_MISMATCH;
  1958. }
  1959. if (Wnode == NULL) {
  1960. return STATUS_INVALID_PARAMETER_MIX;
  1961. }
  1962. TraceHandle = Wnode->HistoricalContext;
  1963. if ((TraceHandle == 0) || (TraceHandle == (ULONG) -1)) {
  1964. return STATUS_INVALID_HANDLE;
  1965. }
  1966. LoggerId = WmiGetLoggerId(TraceHandle);
  1967. if (LoggerId > MAXLOGGERS) {
  1968. return STATUS_INVALID_HANDLE;
  1969. }
  1970. if (TraceInformation) {
  1971. *((PULONG)TraceInformation) = LoggerId;
  1972. }
  1973. if (ARGUMENT_PRESENT( RequiredLength )) {
  1974. *RequiredLength = sizeof( ULONG );
  1975. }
  1976. break;
  1977. case TraceHandleClass:
  1978. if (TraceInformationLength != sizeof(TRACEHANDLE)) {
  1979. return STATUS_INFO_LENGTH_MISMATCH;
  1980. }
  1981. if (Buffer == NULL) {
  1982. return STATUS_INVALID_PARAMETER_MIX;
  1983. }
  1984. LoggerId = *((PULONG) Buffer);
  1985. TraceHandle = 0;
  1986. TraceHandle = WmiSetLoggerId(LoggerId, &TraceHandle);
  1987. if (TraceInformation) {
  1988. *((PTRACEHANDLE)TraceInformation) = TraceHandle;
  1989. }
  1990. if (ARGUMENT_PRESENT( RequiredLength )) {
  1991. *RequiredLength = sizeof( TRACEHANDLE );
  1992. }
  1993. break;
  1994. case TraceEnableFlagsClass:
  1995. if (TraceInformationLength < sizeof(ULONG)) {
  1996. return STATUS_INFO_LENGTH_MISMATCH;
  1997. }
  1998. if (Wnode == NULL) {
  1999. return STATUS_INVALID_PARAMETER_MIX;
  2000. }
  2001. TraceHandle = Wnode->HistoricalContext;
  2002. if ((TraceHandle == 0) || (TraceHandle == (ULONG) -1)) {
  2003. return STATUS_INVALID_HANDLE;
  2004. }
  2005. EnableFlags = WmiGetLoggerEnableFlags(TraceHandle);
  2006. if (TraceInformation) {
  2007. *((PULONG)TraceInformation) = EnableFlags;
  2008. }
  2009. if (ARGUMENT_PRESENT( RequiredLength )) {
  2010. *RequiredLength = sizeof( ULONG );
  2011. }
  2012. break;
  2013. case TraceEnableLevelClass:
  2014. if (TraceInformationLength < sizeof(ULONG)) {
  2015. return STATUS_INFO_LENGTH_MISMATCH;
  2016. }
  2017. if (Wnode == NULL) {
  2018. return STATUS_INVALID_PARAMETER_MIX;
  2019. }
  2020. TraceHandle = Wnode->HistoricalContext;
  2021. if ((TraceHandle == 0) || (TraceHandle == (ULONG) -1)) {
  2022. return STATUS_INVALID_HANDLE;
  2023. }
  2024. EnableLevel = WmiGetLoggerEnableLevel(TraceHandle);
  2025. *((PULONG)TraceInformation) = EnableLevel;
  2026. if (ARGUMENT_PRESENT( RequiredLength )) {
  2027. *RequiredLength = sizeof( ULONG );
  2028. }
  2029. break;
  2030. case GlobalLoggerHandleClass:
  2031. if (TraceInformationLength != sizeof(TRACEHANDLE)) {
  2032. return STATUS_INFO_LENGTH_MISMATCH;
  2033. }
  2034. WmipReferenceLogger(WMI_GLOBAL_LOGGER_ID);
  2035. if (WmipLoggerContext[WMI_GLOBAL_LOGGER_ID] == NULL) {
  2036. TraceHandle = 0;
  2037. Status = STATUS_NOT_FOUND;
  2038. }
  2039. else {
  2040. TraceHandle = WmipLoggerContext[WMI_GLOBAL_LOGGER_ID]->LoggerId;
  2041. }
  2042. WmipDereferenceLogger(WMI_GLOBAL_LOGGER_ID);
  2043. if (TraceInformation) {
  2044. *((PTRACEHANDLE)TraceInformation) = TraceHandle;
  2045. }
  2046. if (ARGUMENT_PRESENT( RequiredLength )) {
  2047. *RequiredLength = sizeof( TRACEHANDLE );
  2048. }
  2049. break;
  2050. case EventLoggerHandleClass:
  2051. if (TraceInformationLength != sizeof(TRACEHANDLE)) {
  2052. return STATUS_INFO_LENGTH_MISMATCH;
  2053. }
  2054. LoggerId = WmipEventLogger;
  2055. if (WmipEventLogger == (ULONG) -1) {
  2056. TraceHandle = 0;
  2057. Status = STATUS_NOT_FOUND;
  2058. }
  2059. else {
  2060. TraceHandle = LoggerId;
  2061. }
  2062. if (TraceInformation) {
  2063. *((PTRACEHANDLE)TraceInformation) = TraceHandle;
  2064. }
  2065. if (ARGUMENT_PRESENT( RequiredLength )) {
  2066. *RequiredLength = sizeof( TRACEHANDLE );
  2067. }
  2068. break;
  2069. case AllLoggerHandlesClass:
  2070. // Returns all logger handles, except for kernel logger
  2071. if (TraceInformationLength < sizeof(TRACEHANDLE)) {
  2072. return STATUS_INFO_LENGTH_MISMATCH;
  2073. }
  2074. LoggersLength = 0;
  2075. for (LoggerId=1; LoggerId<MAXLOGGERS; LoggerId++) {
  2076. WmipReferenceLogger(LoggerId);
  2077. if (!WmipIsValidLogger(WmipLoggerContext[LoggerId])) {
  2078. AllHandles[LoggersLength] = 0;
  2079. }
  2080. else {
  2081. AllHandles[LoggersLength++] = LoggerId;
  2082. }
  2083. WmipDereferenceLogger(LoggerId);
  2084. }
  2085. LoggersLength *= sizeof(TRACEHANDLE);
  2086. if (TraceInformation && (LoggersLength > 0)) {
  2087. if (TraceInformationLength >= LoggersLength) {
  2088. RtlCopyMemory(TraceInformation, AllHandles, LoggersLength);
  2089. }
  2090. else {
  2091. RtlCopyMemory(TraceInformation, AllHandles, TraceInformationLength);
  2092. Status = STATUS_MORE_ENTRIES;
  2093. }
  2094. }
  2095. if (ARGUMENT_PRESENT( RequiredLength )) {
  2096. *RequiredLength = LoggersLength;
  2097. }
  2098. break;
  2099. case TraceHandleByNameClass:
  2100. // Returns a Trace Handle Given a Logger name as a UNICODE_STRING in buffer.
  2101. {
  2102. WMI_LOGGER_INFORMATION LoggerInfo;
  2103. PUNICODE_STRING uString = Buffer;
  2104. if (TraceInformationLength != sizeof(TraceHandle) ) {
  2105. return STATUS_INFO_LENGTH_MISMATCH;
  2106. }
  2107. if (uString == NULL) {
  2108. return STATUS_INVALID_PARAMETER;
  2109. }
  2110. if (uString->Buffer == NULL || uString->Length == 0) {
  2111. return STATUS_INVALID_PARAMETER;
  2112. }
  2113. RtlZeroMemory(&LoggerInfo, sizeof(LoggerInfo));
  2114. LoggerInfo.Wnode.BufferSize = sizeof(LoggerInfo);
  2115. LoggerInfo.Wnode.Flags = WNODE_FLAG_TRACED_GUID;
  2116. RtlInitUnicodeString(&LoggerInfo.LoggerName, uString->Buffer);
  2117. Status = WmiQueryTrace(&LoggerInfo);
  2118. if (!NT_SUCCESS(Status)) {
  2119. return STATUS_NOT_FOUND;
  2120. }
  2121. TraceHandle = (TRACEHANDLE)LoggerInfo.Wnode.HistoricalContext;
  2122. if (TraceInformation) {
  2123. *((PTRACEHANDLE)TraceInformation) = TraceHandle;
  2124. }
  2125. if (ARGUMENT_PRESENT( RequiredLength )) {
  2126. *RequiredLength = sizeof( TRACEHANDLE );
  2127. }
  2128. }
  2129. break;
  2130. default :
  2131. return STATUS_INVALID_INFO_CLASS;
  2132. }
  2133. } except (EXCEPTION_EXECUTE_HANDLER) {
  2134. Status = GetExceptionCode();
  2135. }
  2136. return Status;
  2137. }