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

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