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.

3481 lines
122 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. logsup.c
  5. Abstract:
  6. WMI logger api set. The routines here will need to appear like they
  7. are system calls. They are necessary to do the necessary error checking
  8. and do most of the legwork that can be done outside the kernel. The
  9. kernel portion will subsequently only deal with the actual logging
  10. and tracing.
  11. Author:
  12. 28-May-1997 JeePang
  13. Revision History:
  14. --*/
  15. #ifndef MEMPHIS
  16. #include <nt.h>
  17. #include <ntrtl.h> // for ntutrl.h
  18. #include <nturtl.h> // for RTL_CRITICAL_SECTION in winbase.h/wtypes.h
  19. #include <wtypes.h> // for LPGUID in wmium.h
  20. #include "wmiump.h"
  21. #include "evntrace.h"
  22. #include "traceump.h"
  23. #include "tracelib.h"
  24. #include <math.h>
  25. #include "trcapi.h"
  26. #include "NtdllTrc.h"
  27. #include <strsafe.h>
  28. #include <ntperf.h>
  29. ULONG KernelWow64 = FALSE;
  30. #define CPU_ROOT \
  31. L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor"
  32. #define MHZ_VALUE_NAME \
  33. L"~MHz"
  34. typedef ULONG (WMIAPI HWCONFIG)(PWMI_LOGGER_CONTEXT);
  35. typedef HWCONFIG * PHWCONFIG ;
  36. HWCONFIG EtwpDumpHWConfig;
  37. //
  38. // Initially in ntdll EtwpDumpHardwareConfig points
  39. // to Dummy function EtwpDumpHWConfig
  40. //
  41. PHWCONFIG EtwpDumpHardwareConfig = EtwpDumpHWConfig;
  42. NTSTATUS
  43. EtwpRegQueryValueKey(
  44. IN HANDLE KeyHandle,
  45. IN LPWSTR lpValueName,
  46. IN ULONG Length,
  47. OUT PVOID KeyValue,
  48. OUT PULONG ResultLength
  49. );
  50. NTSTATUS
  51. EtwpProcessRunDown(
  52. IN PWMI_LOGGER_CONTEXT Logger,
  53. IN ULONG StartFlag,
  54. IN ULONG fEnableFlags
  55. );
  56. NTSTATUS
  57. EtwpThreadRunDown(
  58. IN PWMI_LOGGER_CONTEXT Logger,
  59. IN PSYSTEM_PROCESS_INFORMATION pProcessInfo,
  60. IN ULONG StartFlag,
  61. IN BOOLEAN bExtended
  62. );
  63. extern
  64. NTSTATUS
  65. DumpHeapSnapShot(
  66. IN PWMI_LOGGER_CONTEXT Logger
  67. );
  68. ULONG
  69. EtwpDumpHWConfig(
  70. IN PWMI_LOGGER_CONTEXT LoggerContext
  71. )
  72. {
  73. return STATUS_SUCCESS;
  74. }
  75. //
  76. // This function is called when advapi32.dll loads
  77. // into process memory and gives ntdll the pointer
  78. // of function in advapi32 which traces the infor-
  79. // mation of System configuration
  80. //
  81. void EtwpSetHWConfigFunction(PHWCONFIG DumpHardwareConfig, ULONG Reason)
  82. {
  83. if (Reason == DLL_PROCESS_ATTACH)
  84. {
  85. //
  86. // On DLL Laod Get the pointer in Advapi32.dll
  87. //
  88. EtwpDumpHardwareConfig = DumpHardwareConfig;
  89. } else {
  90. //
  91. // On DLL unload point it back to Dummy function.
  92. //
  93. EtwpDumpHardwareConfig = EtwpDumpHWConfig;
  94. }
  95. }
  96. __inline __int64 EtwpGetSystemTime()
  97. {
  98. LARGE_INTEGER SystemTime;
  99. //
  100. // Read system time from shared region.
  101. //
  102. do {
  103. SystemTime.HighPart = USER_SHARED_DATA->SystemTime.High1Time;
  104. SystemTime.LowPart = USER_SHARED_DATA->SystemTime.LowPart;
  105. } while (SystemTime.HighPart != USER_SHARED_DATA->SystemTime.High2Time);
  106. return SystemTime.QuadPart;
  107. }
  108. ULONG WmiTraceAlignment = DEFAULT_TRACE_ALIGNMENT;
  109. ULONG
  110. EtwpStartLogger(
  111. IN OUT PWMI_LOGGER_INFORMATION LoggerInfo
  112. )
  113. /*++
  114. Routine Description:
  115. This is the actual routine to communicate with the kernel to start
  116. the logger. All the required parameters must be in LoggerInfo.
  117. Arguments:
  118. LoggerInfo The actual parameters to be passed to and return from
  119. kernel.
  120. Return Value:
  121. The status of performing the action requested.
  122. --*/
  123. {
  124. ULONG Status;
  125. ULONG BufferSize;
  126. LPGUID Guid;
  127. PVOID SavedChecksum;
  128. ULONG SavedLogFileMode;
  129. BOOLEAN IsKernelTrace = FALSE;
  130. BOOLEAN bLogFile = FALSE;
  131. BOOLEAN bRealTime = FALSE;
  132. WMI_REF_CLOCK RefClock;
  133. LARGE_INTEGER RefClockSys, RefClockPerf, RefClockCycle;
  134. LARGE_INTEGER Frequency;
  135. Guid = &LoggerInfo->Wnode.Guid;
  136. if( IsEqualGUID(&HeapGuid,Guid)
  137. || IsEqualGUID(&CritSecGuid,Guid)
  138. ){
  139. WMINTDLLLOGGERINFO NtdllLoggerInfo;
  140. NtdllLoggerInfo.LoggerInfo = LoggerInfo;
  141. RtlCopyMemory(&LoggerInfo->Wnode.Guid, &NtdllTraceGuid, sizeof(GUID));
  142. NtdllLoggerInfo.IsGet = FALSE;
  143. Status = EtwpSendWmiKMRequest(
  144. NULL,
  145. IOCTL_WMI_NTDLL_LOGGERINFO,
  146. &NtdllLoggerInfo,
  147. sizeof(WMINTDLLLOGGERINFO),
  148. &NtdllLoggerInfo,
  149. sizeof(WMINTDLLLOGGERINFO),
  150. &BufferSize,
  151. NULL
  152. );
  153. return EtwpSetDosError(Status);
  154. }
  155. if (IsEqualGUID(Guid, &SystemTraceControlGuid) ||
  156. IsEqualGUID(Guid, &WmiEventLoggerGuid)) {
  157. IsKernelTrace = TRUE;
  158. }
  159. if ((LoggerInfo->LogFileName.Length > 0) &&
  160. (LoggerInfo->LogFileName.Buffer != NULL)) {
  161. bLogFile = TRUE;
  162. }
  163. SavedLogFileMode = LoggerInfo->LogFileMode;
  164. if (SavedLogFileMode & EVENT_TRACE_REAL_TIME_MODE) {
  165. bRealTime = TRUE;
  166. }
  167. //
  168. // If the user didn't specify the clock type, set the default clock type
  169. // system time.
  170. //
  171. if (LoggerInfo->Wnode.ClientContext != EVENT_TRACE_CLOCK_PERFCOUNTER &&
  172. LoggerInfo->Wnode.ClientContext != EVENT_TRACE_CLOCK_SYSTEMTIME &&
  173. LoggerInfo->Wnode.ClientContext != EVENT_TRACE_CLOCK_CPUCYCLE) {
  174. LoggerInfo->Wnode.ClientContext = EVENT_TRACE_CLOCK_SYSTEMTIME;
  175. }
  176. //
  177. // Take a reference timestamp before actually starting the logger. This is
  178. // due to the fact that the Kernel logger can pump events with timestamps
  179. // earier than the LogFileHeader Timestamp. As a result we take the
  180. // reference timestamps prior to starting anything.
  181. //
  182. RefClockSys.QuadPart = EtwpGetSystemTime();
  183. RefClockCycle.QuadPart = EtwpGetCycleCount();
  184. Status = NtQueryPerformanceCounter(&RefClockPerf, &Frequency);
  185. if (SavedLogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) {
  186. Status = EtwpSendUmLogRequest(
  187. WmiStartLoggerCode,
  188. LoggerInfo
  189. );
  190. }
  191. else if (IsKernelTrace) {
  192. //
  193. // In order to capture the process/thread rundown accurately, we need to
  194. // start kernel logger in two steps. Start logger with delay write,
  195. // do rundown from user mode and then updatelogger with filename.
  196. //
  197. WMI_LOGGER_INFORMATION DelayLoggerInfo;
  198. ULONG EnableFlags = LoggerInfo->EnableFlags;
  199. //
  200. // If it's only realtime start logger in one step
  201. //
  202. if (bRealTime && !bLogFile) {
  203. Status = EtwpSendWmiKMRequest(
  204. NULL,
  205. IOCTL_WMI_START_LOGGER,
  206. LoggerInfo,
  207. LoggerInfo->Wnode.BufferSize,
  208. LoggerInfo,
  209. LoggerInfo->Wnode.BufferSize,
  210. &BufferSize,
  211. NULL
  212. );
  213. return EtwpSetDosError(Status);
  214. }
  215. if (EnableFlags & EVENT_TRACE_FLAG_EXTENSION) {
  216. PTRACE_ENABLE_FLAG_EXTENSION tFlagExt;
  217. tFlagExt = (PTRACE_ENABLE_FLAG_EXTENSION)
  218. &LoggerInfo->EnableFlags;
  219. EnableFlags = *(PULONG)((PCHAR)LoggerInfo + tFlagExt->Offset);
  220. }
  221. RtlCopyMemory(&DelayLoggerInfo,
  222. LoggerInfo,
  223. sizeof(WMI_LOGGER_INFORMATION));
  224. RtlZeroMemory(&DelayLoggerInfo.LogFileName, sizeof(UNICODE_STRING) );
  225. DelayLoggerInfo.Wnode.BufferSize = sizeof(WMI_LOGGER_INFORMATION);
  226. DelayLoggerInfo.LogFileMode |= EVENT_TRACE_DELAY_OPEN_FILE_MODE;
  227. //
  228. // Since there's no filename in step 1 of StartLogger we need to mask
  229. // the NEWFILE mode to prevent kernel trying to generate a file
  230. //
  231. DelayLoggerInfo.LogFileMode &= ~EVENT_TRACE_FILE_MODE_NEWFILE;
  232. DelayLoggerInfo.EnableFlags = (EVENT_TRACE_FLAG_PROCESS & EnableFlags);
  233. DelayLoggerInfo.EnableFlags |= (EVENT_TRACE_FLAG_THREAD & EnableFlags);
  234. DelayLoggerInfo.EnableFlags |=
  235. (EVENT_TRACE_FLAG_IMAGE_LOAD & EnableFlags);
  236. Status = EtwpSendWmiKMRequest(
  237. NULL,
  238. IOCTL_WMI_START_LOGGER,
  239. &DelayLoggerInfo,
  240. DelayLoggerInfo.Wnode.BufferSize,
  241. &DelayLoggerInfo,
  242. DelayLoggerInfo.Wnode.BufferSize,
  243. &BufferSize,
  244. NULL
  245. );
  246. if (Status != ERROR_SUCCESS) {
  247. return Status;
  248. }
  249. LoggerInfo->Wnode.ClientContext = DelayLoggerInfo.Wnode.ClientContext;
  250. //
  251. // We need to pick up any parameter adjustment done by the kernel
  252. // here so UpdateTrace does not fail.
  253. //
  254. LoggerInfo->Wnode.HistoricalContext =
  255. DelayLoggerInfo.Wnode.HistoricalContext;
  256. LoggerInfo->MinimumBuffers = DelayLoggerInfo.MinimumBuffers;
  257. LoggerInfo->MaximumBuffers = DelayLoggerInfo.MaximumBuffers;
  258. LoggerInfo->NumberOfBuffers = DelayLoggerInfo.NumberOfBuffers;
  259. LoggerInfo->BufferSize = DelayLoggerInfo.BufferSize;
  260. LoggerInfo->AgeLimit = DelayLoggerInfo.AgeLimit;
  261. BufferSize = LoggerInfo->BufferSize * 1024;
  262. //
  263. // Add the LogHeader
  264. //
  265. LoggerInfo->Checksum = NULL;
  266. if (LoggerInfo->Wnode.ClientContext == EVENT_TRACE_CLOCK_PERFCOUNTER) {
  267. RefClock.StartPerfClock = RefClockPerf;
  268. } else if (LoggerInfo->Wnode.ClientContext ==
  269. EVENT_TRACE_CLOCK_CPUCYCLE) {
  270. RefClock.StartPerfClock= RefClockCycle;
  271. } else {
  272. RefClock.StartPerfClock = RefClockSys;
  273. }
  274. RefClock.StartTime = RefClockSys;
  275. Status = EtwpAddLogHeaderToLogFile(LoggerInfo, &RefClock, FALSE);
  276. if (Status == ERROR_SUCCESS) {
  277. SavedChecksum = LoggerInfo->Checksum;
  278. //
  279. // Update the logger with the filename
  280. //
  281. Status = EtwpSendWmiKMRequest(
  282. NULL,
  283. IOCTL_WMI_UPDATE_LOGGER,
  284. LoggerInfo,
  285. LoggerInfo->Wnode.BufferSize,
  286. LoggerInfo,
  287. LoggerInfo->Wnode.BufferSize,
  288. &BufferSize,
  289. NULL
  290. );
  291. if (SavedChecksum != NULL) {
  292. EtwpFree(SavedChecksum);
  293. SavedChecksum = NULL;
  294. }
  295. }
  296. if (Status != ERROR_SUCCESS) {
  297. ULONG lStatus;
  298. //
  299. // Logger must be stopped now
  300. //
  301. lStatus = EtwpSendWmiKMRequest(
  302. NULL,
  303. IOCTL_WMI_STOP_LOGGER,
  304. LoggerInfo,
  305. LoggerInfo->Wnode.BufferSize,
  306. LoggerInfo,
  307. LoggerInfo->Wnode.BufferSize,
  308. &BufferSize,
  309. NULL
  310. );
  311. LoggerInfo->LogFileMode = SavedLogFileMode;
  312. return EtwpSetDosError(Status);
  313. }
  314. }
  315. else {
  316. LoggerInfo->Checksum = NULL;
  317. //
  318. // Query for supported clock types. If an unsupported clock type
  319. // is specified this LoggerInfo will contain the kernel's default
  320. //
  321. Status = EtwpSendWmiKMRequest(NULL,
  322. IOCTL_WMI_CLOCK_TYPE,
  323. LoggerInfo,
  324. LoggerInfo->Wnode.BufferSize,
  325. LoggerInfo,
  326. LoggerInfo->Wnode.BufferSize,
  327. &BufferSize,
  328. NULL
  329. );
  330. if (Status != ERROR_SUCCESS) {
  331. return EtwpSetDosError(Status);
  332. }
  333. if (LoggerInfo->Wnode.ClientContext == EVENT_TRACE_CLOCK_PERFCOUNTER) {
  334. RefClock.StartPerfClock = RefClockPerf;
  335. } else if (LoggerInfo->Wnode.ClientContext == EVENT_TRACE_CLOCK_CPUCYCLE) {
  336. RefClock.StartPerfClock= RefClockCycle;
  337. } else {
  338. RefClock.StartPerfClock = RefClockSys;
  339. }
  340. RefClock.StartTime = RefClockSys;
  341. Status = EtwpAddLogHeaderToLogFile(LoggerInfo, &RefClock, FALSE);
  342. if (Status != ERROR_SUCCESS) {
  343. return EtwpSetDosError(Status);
  344. }
  345. //
  346. // At this point we have an open handle to the logfile and memory
  347. // allocation?
  348. //
  349. BufferSize = LoggerInfo->BufferSize * 1024;
  350. SavedChecksum = LoggerInfo->Checksum;
  351. // actually start the logger here
  352. Status = EtwpSendWmiKMRequest(
  353. NULL,
  354. IOCTL_WMI_START_LOGGER,
  355. LoggerInfo,
  356. LoggerInfo->Wnode.BufferSize,
  357. LoggerInfo,
  358. LoggerInfo->Wnode.BufferSize,
  359. &BufferSize,
  360. NULL
  361. );
  362. // Close the handle if it's not NULL
  363. if (LoggerInfo->LogFileHandle != NULL) {
  364. NtClose(LoggerInfo->LogFileHandle);
  365. LoggerInfo->LogFileHandle = NULL;
  366. }
  367. //
  368. // If the Start call failed, we will delete the logfile except
  369. // when we are appending to an older file. However, we do not
  370. // fixup the header!
  371. //
  372. if ( (Status != ERROR_MORE_DATA) &&
  373. !(LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_APPEND)) {
  374. if (LoggerInfo->LogFileName.Buffer != NULL) {
  375. EtwpDeleteFileW(LoggerInfo->LogFileName.Buffer);
  376. }
  377. }
  378. if (SavedChecksum != NULL) {
  379. EtwpFree(SavedChecksum);
  380. }
  381. }
  382. //
  383. // Restore the LogFileMode
  384. //
  385. LoggerInfo->LogFileMode = SavedLogFileMode;
  386. return EtwpSetDosError(Status);
  387. }
  388. ULONG
  389. EtwpFinalizeLogFileHeader(
  390. IN PWMI_LOGGER_INFORMATION LoggerInfo
  391. )
  392. {
  393. ULONG Status = ERROR_SUCCESS;
  394. ULONG ErrorCode = ERROR_SUCCESS;
  395. HANDLE LogFile = INVALID_HANDLE_VALUE;
  396. LARGE_INTEGER CurrentTime;
  397. WMI_LOGGER_CONTEXT Logger;
  398. IO_STATUS_BLOCK IoStatus;
  399. FILE_POSITION_INFORMATION FileInfo;
  400. FILE_STANDARD_INFORMATION FileSize;
  401. PWMI_BUFFER_HEADER Buffer; // need to initialize buffer first
  402. SYSTEM_BASIC_INFORMATION SystemInfo;
  403. ULONG EnableFlags;
  404. ULONG IsKernelTrace = FALSE;
  405. ULONG IsGlobalForKernel = FALSE;
  406. USHORT LoggerId = 0;
  407. RtlZeroMemory(&Logger, sizeof(WMI_LOGGER_CONTEXT));
  408. Logger.BufferSpace = NULL;
  409. IsKernelTrace = IsEqualGUID(&LoggerInfo->Wnode.Guid,
  410. &SystemTraceControlGuid);
  411. if (LoggerInfo->LogFileName.Length > 0 ) {
  412. // open the file for writing synchronously for the logger
  413. // others may want to read it as well.
  414. //
  415. LogFile = EtwpCreateFileW(
  416. (LPWSTR)LoggerInfo->LogFileName.Buffer,
  417. GENERIC_READ | GENERIC_WRITE,
  418. FILE_SHARE_READ,
  419. NULL,
  420. OPEN_EXISTING,
  421. FILE_ATTRIBUTE_NORMAL,
  422. NULL
  423. );
  424. if (LogFile == INVALID_HANDLE_VALUE) {
  425. ErrorCode = EtwpGetLastError();
  426. goto cleanup;
  427. }
  428. // Truncate the file size if in PREALLOCATE mode
  429. if (LoggerInfo->MaximumFileSize &&
  430. (LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_PREALLOCATE)) {
  431. IO_STATUS_BLOCK IoStatusBlock;
  432. FILE_END_OF_FILE_INFORMATION EOFInfo;
  433. // Do this only when we haven't reach the max file size
  434. if (!(LoggerInfo->LogFileMode & EVENT_TRACE_USE_KBYTES_FOR_SIZE)) {
  435. if (LoggerInfo->MaximumFileSize >
  436. (((ULONGLONG)LoggerInfo->BuffersWritten *
  437. (ULONGLONG)LoggerInfo->BufferSize) /
  438. 1024)) {
  439. EOFInfo.EndOfFile.QuadPart =
  440. (ULONGLONG)LoggerInfo->BuffersWritten *
  441. (ULONGLONG)LoggerInfo->BufferSize *
  442. 1024;
  443. Status = NtSetInformationFile(LogFile,
  444. &IoStatusBlock,
  445. &EOFInfo,
  446. sizeof(FILE_END_OF_FILE_INFORMATION),
  447. FileEndOfFileInformation
  448. );
  449. if (!NT_SUCCESS(Status)) {
  450. NtClose(LogFile);
  451. ErrorCode = EtwpNtStatusToDosError(Status);
  452. goto cleanup;
  453. }
  454. }
  455. }
  456. else { // using KBytes for file size unit
  457. if (LoggerInfo->MaximumFileSize >
  458. ((ULONGLONG)LoggerInfo->BuffersWritten *
  459. (ULONGLONG)LoggerInfo->BufferSize)) { //
  460. EOFInfo.EndOfFile.QuadPart =
  461. (ULONGLONG)LoggerInfo->BuffersWritten *
  462. (ULONGLONG)LoggerInfo->BufferSize *
  463. 1024;
  464. Status = NtSetInformationFile(
  465. LogFile,
  466. &IoStatusBlock,
  467. &EOFInfo,
  468. sizeof(FILE_END_OF_FILE_INFORMATION),
  469. FileEndOfFileInformation
  470. );
  471. if (!NT_SUCCESS(Status)) {
  472. NtClose(LogFile);
  473. ErrorCode = EtwpNtStatusToDosError(Status);
  474. goto cleanup;
  475. }
  476. }
  477. }
  478. }
  479. Logger.BuffersWritten = LoggerInfo->BuffersWritten;
  480. Logger.BufferSpace = EtwpAlloc(LoggerInfo->BufferSize * 1024);
  481. if (Logger.BufferSpace == NULL) {
  482. ErrorCode = EtwpSetDosError(ERROR_NOT_ENOUGH_MEMORY);
  483. goto cleanup;
  484. }
  485. Buffer = (PWMI_BUFFER_HEADER) Logger.BufferSpace;
  486. RtlZeroMemory(Buffer, LoggerInfo->BufferSize * 1024);
  487. Buffer->Wnode.BufferSize = LoggerInfo->BufferSize * 1024;
  488. Buffer->ClientContext.Alignment = (UCHAR)WmiTraceAlignment;
  489. Buffer->Offset = sizeof(WMI_BUFFER_HEADER);
  490. Buffer->Wnode.Guid = LoggerInfo->Wnode.Guid;
  491. Status = NtQuerySystemInformation(
  492. SystemBasicInformation,
  493. &SystemInfo, sizeof (SystemInfo), NULL);
  494. if (!NT_SUCCESS(Status)) {
  495. ErrorCode = EtwpNtStatusToDosError(Status);
  496. goto cleanup;
  497. }
  498. Logger.TimerResolution = SystemInfo.TimerResolution;
  499. Logger.LogFileHandle = LogFile;
  500. Logger.BufferSize = LoggerInfo->BufferSize * 1024;
  501. // For Circular LogFile the process rundown data is appended at the
  502. // last buffer written and not to the end of file.
  503. //
  504. Status = NtQueryInformationFile(
  505. LogFile,
  506. &IoStatus,
  507. &FileSize,
  508. sizeof(FILE_STANDARD_INFORMATION),
  509. FileStandardInformation
  510. );
  511. if (!NT_SUCCESS(Status)) {
  512. ErrorCode = EtwpNtStatusToDosError(Status);
  513. goto cleanup;
  514. }
  515. //
  516. // For Kernel Boot Traces, we need to do the Rundown.
  517. // configuration at this time.
  518. // 1. The Logger ID is GLOBAL_LOGGER_ID
  519. // 2. The LoggerName is NT_KERNEL_LOGGER
  520. //
  521. // The First condition is true for any GlobalLogger but
  522. // condition 2 is TRUE only when it is collecting kernel traces.
  523. //
  524. LoggerId = WmiGetLoggerId (LoggerInfo->Wnode.HistoricalContext);
  525. if ( (LoggerId == WMI_GLOBAL_LOGGER_ID) &&
  526. (LoggerInfo->LoggerName.Length > 0) &&
  527. (LoggerInfo->LoggerName.Buffer != NULL) &&
  528. (!wcscmp(LoggerInfo->LoggerName.Buffer, KERNEL_LOGGER_NAMEW))
  529. ) {
  530. IsGlobalForKernel = TRUE;
  531. }
  532. if ( IsKernelTrace || IsGlobalForKernel ) {
  533. if (IsGlobalForKernel) {
  534. ULONG CpuSpeed;
  535. ULONG CpuNum = 0;
  536. //
  537. // For boot traces we need to re-set the CPU Speed in the
  538. // log file header as it is not available in the registry
  539. // when the log file header is first created.
  540. //
  541. if (NT_SUCCESS(EtwpGetCpuSpeed(&CpuNum, &CpuSpeed))) {
  542. FileInfo.CurrentByteOffset.QuadPart =
  543. LOGFILE_FIELD_OFFSET(CpuSpeedInMHz);
  544. Status = NtSetInformationFile(
  545. LogFile,
  546. &IoStatus,
  547. &FileInfo,
  548. sizeof(FILE_POSITION_INFORMATION),
  549. FilePositionInformation
  550. );
  551. if (!NT_SUCCESS(Status)) {
  552. ErrorCode = EtwpNtStatusToDosError(Status);
  553. goto cleanup;
  554. }
  555. Status = NtWriteFile(
  556. LogFile,
  557. NULL,
  558. NULL,
  559. NULL,
  560. &IoStatus,
  561. &CpuSpeed,
  562. sizeof(CpuSpeed),
  563. NULL,
  564. NULL
  565. );
  566. if (NT_SUCCESS(Status)) {
  567. NtFlushBuffersFile(Logger.LogFileHandle, &IoStatus);
  568. }
  569. }
  570. }
  571. if (sizeof(PVOID) != 8) {
  572. // For kernel trace, the pointer size is always 64 on ia64,
  573. // whether or not under Wow64. Get Wow64 information and set
  574. // the flag so that ProcessRunDown can dajust pointer size.
  575. ULONG_PTR ulp;
  576. Status = NtQueryInformationProcess(
  577. NtCurrentProcess(),
  578. ProcessWow64Information,
  579. &ulp,
  580. sizeof(ULONG_PTR),
  581. NULL);
  582. if (NT_SUCCESS(Status) && (ulp != 0)) {
  583. KernelWow64 = TRUE;
  584. }
  585. }
  586. if (LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_CIRCULAR) {
  587. ULONG BufferSize = LoggerInfo->BufferSize; // in KB
  588. ULONG BuffersWritten = LoggerInfo->BuffersWritten;
  589. ULONG maxBuffers = (LoggerInfo->MaximumFileSize *
  590. 1024) /
  591. BufferSize;
  592. ULONG LastBuffer;
  593. ULONG StartBuffers;
  594. FileInfo.CurrentByteOffset.QuadPart =
  595. LOGFILE_FIELD_OFFSET(StartBuffers);
  596. Status = NtSetInformationFile(
  597. LogFile,
  598. &IoStatus,
  599. &FileInfo,
  600. sizeof(FILE_POSITION_INFORMATION),
  601. FilePositionInformation
  602. );
  603. if (!NT_SUCCESS(Status)) {
  604. ErrorCode = EtwpNtStatusToDosError(Status);
  605. goto cleanup;
  606. }
  607. Status = NtReadFile(
  608. LogFile,
  609. NULL,
  610. NULL,
  611. NULL,
  612. &IoStatus,
  613. &StartBuffers,
  614. sizeof(ULONG),
  615. NULL,
  616. NULL
  617. );
  618. if (!NT_SUCCESS(Status)) {
  619. ErrorCode = EtwpNtStatusToDosError(Status);
  620. goto cleanup;
  621. }
  622. LastBuffer = (maxBuffers > StartBuffers) ?
  623. (StartBuffers + (BuffersWritten - StartBuffers)
  624. % (maxBuffers - StartBuffers))
  625. : 0;
  626. FileInfo.CurrentByteOffset.QuadPart = LastBuffer *
  627. BufferSize * 1024;
  628. }
  629. else {
  630. FileInfo.CurrentByteOffset = FileSize.EndOfFile;
  631. }
  632. Status = NtSetInformationFile(
  633. LogFile,
  634. &IoStatus,
  635. &FileInfo,
  636. sizeof(FILE_POSITION_INFORMATION),
  637. FilePositionInformation
  638. );
  639. if (!NT_SUCCESS(Status)) {
  640. ErrorCode = EtwpNtStatusToDosError(Status);
  641. goto cleanup;
  642. }
  643. EnableFlags = LoggerInfo->EnableFlags;
  644. if (EnableFlags & EVENT_TRACE_FLAG_EXTENSION) {
  645. PTRACE_ENABLE_FLAG_EXTENSION tFlagExt;
  646. tFlagExt = (PTRACE_ENABLE_FLAG_EXTENSION)
  647. &LoggerInfo->EnableFlags;
  648. if (LoggerInfo->Wnode.BufferSize >= (tFlagExt->Offset + sizeof(ULONG)) ) {
  649. EnableFlags = *(PULONG)((PCHAR)LoggerInfo + tFlagExt->Offset);
  650. }
  651. else {
  652. EnableFlags = 0; // Should not happen.
  653. }
  654. }
  655. Logger.UsePerfClock = LoggerInfo->Wnode.ClientContext;
  656. EtwpProcessRunDown(&Logger, FALSE, EnableFlags);
  657. if (IsGlobalForKernel) {
  658. EtwpDumpHardwareConfig(&Logger);
  659. }
  660. {
  661. PWMI_BUFFER_HEADER Buffer1 =
  662. (PWMI_BUFFER_HEADER) Logger.BufferSpace;
  663. if (Buffer1->Offset < Logger.BufferSize) {
  664. RtlFillMemory(
  665. (char *) Logger.BufferSpace + Buffer1->Offset,
  666. Logger.BufferSize - Buffer1->Offset,
  667. 0xFF);
  668. }
  669. }
  670. Status = NtWriteFile(
  671. LogFile,
  672. NULL,
  673. NULL,
  674. NULL,
  675. &IoStatus,
  676. Logger.BufferSpace,
  677. Logger.BufferSize,
  678. NULL,
  679. NULL);
  680. if (NT_SUCCESS(Status)) {
  681. NtFlushBuffersFile(Logger.LogFileHandle, &IoStatus);
  682. Logger.BuffersWritten++;
  683. }
  684. }
  685. // Update the EndTime stamp field in LogFile. No Need to
  686. // to do it if it's Relogged File. The old logfile
  687. // header already has the correct value.
  688. //
  689. if ( !(LoggerInfo->LogFileMode & EVENT_TRACE_RELOG_MODE) ) {
  690. FileInfo.CurrentByteOffset.QuadPart =
  691. LOGFILE_FIELD_OFFSET(EndTime);
  692. Status = NtSetInformationFile(
  693. LogFile,
  694. &IoStatus,
  695. &FileInfo,
  696. sizeof(FILE_POSITION_INFORMATION),
  697. FilePositionInformation
  698. );
  699. if (!NT_SUCCESS(Status)) {
  700. ErrorCode = EtwpNtStatusToDosError(Status);
  701. goto cleanup;
  702. }
  703. // End Time is always wallclock time.
  704. //
  705. CurrentTime.QuadPart = EtwpGetSystemTime();
  706. Status = NtWriteFile(
  707. LogFile,
  708. NULL,
  709. NULL,
  710. NULL,
  711. &IoStatus,
  712. &CurrentTime,
  713. sizeof(ULONGLONG),
  714. NULL,
  715. NULL
  716. );
  717. if (NT_SUCCESS(Status)) {
  718. NtFlushBuffersFile(Logger.LogFileHandle, &IoStatus);
  719. }
  720. }
  721. //
  722. // Update the Number of Buffers Written field in the header
  723. //
  724. FileInfo.CurrentByteOffset.QuadPart =
  725. LOGFILE_FIELD_OFFSET(BuffersWritten);
  726. Status = NtSetInformationFile(
  727. LogFile,
  728. &IoStatus,
  729. &FileInfo,
  730. sizeof(FILE_POSITION_INFORMATION),
  731. FilePositionInformation
  732. );
  733. if (!NT_SUCCESS(Status)) {
  734. ErrorCode = EtwpNtStatusToDosError(Status);
  735. goto cleanup;
  736. }
  737. Status = NtWriteFile(
  738. LogFile,
  739. NULL,
  740. NULL,
  741. NULL,
  742. &IoStatus,
  743. &Logger.BuffersWritten,
  744. sizeof(ULONG),
  745. NULL,
  746. NULL
  747. );
  748. if (NT_SUCCESS(Status)) {
  749. NtFlushBuffersFile(Logger.LogFileHandle, &IoStatus);
  750. }
  751. ErrorCode = RtlNtStatusToDosError(Status);
  752. LoggerInfo->BuffersWritten = Logger.BuffersWritten;
  753. if ( !(LoggerInfo->LogFileMode & EVENT_TRACE_RELOG_MODE) ) {
  754. //
  755. // Write the BuffersLost information into the logfile
  756. // We need to be careful for WOW cases because BuffersLost
  757. // come after pointers in log file header.
  758. //
  759. if (KernelWow64) { // KernelWow64
  760. FileInfo.CurrentByteOffset.QuadPart =
  761. LOGFILE_FIELD_OFFSET(BuffersLost) + 8;
  762. }
  763. else if ( LoggerInfo->Wow && 8 == sizeof(PVOID) &&
  764. !(IsKernelTrace || IsGlobalForKernel) ) {
  765. // We're stopping a non-kernel 32 bit logger in 64 bit mode.
  766. // The log file header in the file is 32 bit so we need to
  767. // adjust the field offset.
  768. FileInfo.CurrentByteOffset.QuadPart =
  769. LOGFILE_FIELD_OFFSET(BuffersLost) - 8;
  770. }
  771. else if ( !(LoggerInfo->Wow) && 4 == sizeof(PVOID) &&
  772. !(IsKernelTrace || IsGlobalForKernel) ) {
  773. // We're stopping a non-kernel logger in 32 bit mode.
  774. // If this is running on IA64, the log file header in the file is
  775. // 64 bit so we need to adjust the field offset.
  776. ULONG_PTR ulp;
  777. Status = NtQueryInformationProcess(
  778. NtCurrentProcess(),
  779. ProcessWow64Information,
  780. &ulp,
  781. sizeof(ULONG_PTR),
  782. NULL);
  783. if (NT_SUCCESS(Status) && (ulp != 0)) { // Current process is WOW (on IA64)
  784. FileInfo.CurrentByteOffset.QuadPart =
  785. LOGFILE_FIELD_OFFSET(BuffersLost) + 8;
  786. }
  787. else { // normal x86 case
  788. FileInfo.CurrentByteOffset.QuadPart =
  789. LOGFILE_FIELD_OFFSET(BuffersLost);
  790. }
  791. }
  792. else {
  793. FileInfo.CurrentByteOffset.QuadPart =
  794. LOGFILE_FIELD_OFFSET(BuffersLost);
  795. }
  796. Status = NtSetInformationFile(
  797. LogFile,
  798. &IoStatus,
  799. &FileInfo,
  800. sizeof(FILE_POSITION_INFORMATION),
  801. FilePositionInformation
  802. );
  803. if (!NT_SUCCESS(Status)) {
  804. ErrorCode = EtwpNtStatusToDosError(Status);
  805. goto cleanup;
  806. }
  807. Status = NtWriteFile(
  808. LogFile,
  809. NULL,
  810. NULL,
  811. NULL,
  812. &IoStatus,
  813. &LoggerInfo->LogBuffersLost,
  814. sizeof(ULONG),
  815. NULL,
  816. NULL
  817. );
  818. if (NT_SUCCESS(Status)) {
  819. NtFlushBuffersFile(Logger.LogFileHandle, &IoStatus);
  820. }
  821. //
  822. // Write the EventsLost information into the logfile
  823. //
  824. FileInfo.CurrentByteOffset.QuadPart =
  825. LOGFILE_FIELD_OFFSET(EventsLost);
  826. Status = NtSetInformationFile(
  827. LogFile,
  828. &IoStatus,
  829. &FileInfo,
  830. sizeof(FILE_POSITION_INFORMATION),
  831. FilePositionInformation
  832. );
  833. if (!NT_SUCCESS(Status)) {
  834. ErrorCode = EtwpNtStatusToDosError(Status);
  835. goto cleanup;
  836. }
  837. Status = NtWriteFile(
  838. LogFile,
  839. NULL,
  840. NULL,
  841. NULL,
  842. &IoStatus,
  843. &LoggerInfo->EventsLost,
  844. sizeof(ULONG),
  845. NULL,
  846. NULL
  847. );
  848. if (NT_SUCCESS(Status)) {
  849. NtFlushBuffersFile(Logger.LogFileHandle, &IoStatus);
  850. }
  851. }
  852. }
  853. cleanup:
  854. if (LogFile != INVALID_HANDLE_VALUE) {
  855. NtClose(LogFile);
  856. }
  857. if (Logger.BufferSpace != NULL) {
  858. EtwpFree(Logger.BufferSpace);
  859. }
  860. return EtwpSetDosError(ErrorCode);
  861. }
  862. ULONG
  863. EtwpStopLogger(
  864. IN OUT PWMI_LOGGER_INFORMATION LoggerInfo
  865. )
  866. /*++
  867. Routine Description:
  868. This is the actual routine to communicate with the kernel to stop
  869. the logger. All the properties of the logger will be returned in LoggerInfo.
  870. Arguments:
  871. LoggerInfo The actual parameters to be passed to and return from
  872. kernel.
  873. Return Value:
  874. The status of performing the action requested.
  875. --*/
  876. {
  877. ULONG ErrorCode, ReturnSize;
  878. PTRACE_ENABLE_CONTEXT pContext;
  879. //
  880. //Check For Heap and Crit Sec Guid.
  881. //
  882. if( IsEqualGUID(&HeapGuid,&LoggerInfo->Wnode.Guid)
  883. || IsEqualGUID(&CritSecGuid,&LoggerInfo->Wnode.Guid)
  884. ){
  885. WMINTDLLLOGGERINFO NtdllLoggerInfo;
  886. ULONG BufferSize;
  887. LoggerInfo->Wnode.BufferSize = 0;
  888. RtlCopyMemory(&LoggerInfo->Wnode.Guid, &NtdllTraceGuid, sizeof(GUID));
  889. NtdllLoggerInfo.LoggerInfo = LoggerInfo;
  890. NtdllLoggerInfo.IsGet = FALSE;
  891. ErrorCode = EtwpSendWmiKMRequest(
  892. NULL,
  893. IOCTL_WMI_NTDLL_LOGGERINFO,
  894. &NtdllLoggerInfo,
  895. sizeof(WMINTDLLLOGGERINFO),
  896. &NtdllLoggerInfo,
  897. sizeof(WMINTDLLLOGGERINFO),
  898. &BufferSize,
  899. NULL
  900. );
  901. return EtwpSetDosError(ErrorCode);
  902. }
  903. // pContext = (PTRACE_ENABLE_CONTEXT) & LoggerInfo->Wnode.HistoricalContext;
  904. // if ( (pContext->InternalFlag != 0)
  905. // && (pContext->InternalFlag != EVENT_TRACE_INTERNAL_FLAG_PRIVATE)) {
  906. // // Currently only one possible InternalFlag value. This will filter
  907. // // out some bogus LoggerHandle
  908. // //
  909. // return EtwpSetDosError(ERROR_INVALID_HANDLE);
  910. // }
  911. if (LoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) {
  912. pContext = (PTRACE_ENABLE_CONTEXT) &LoggerInfo->Wnode.HistoricalContext;
  913. pContext->InternalFlag |= EVENT_TRACE_INTERNAL_FLAG_PRIVATE;
  914. pContext->LoggerId = 1;
  915. ErrorCode = EtwpSendUmLogRequest(WmiStopLoggerCode, LoggerInfo);
  916. }
  917. else {
  918. ErrorCode = EtwpSendWmiKMRequest(
  919. NULL,
  920. IOCTL_WMI_STOP_LOGGER,
  921. LoggerInfo,
  922. LoggerInfo->Wnode.BufferSize,
  923. LoggerInfo,
  924. LoggerInfo->Wnode.BufferSize,
  925. &ReturnSize,
  926. NULL
  927. );
  928. //
  929. // if logging to a file, then update the EndTime, BuffersWritten and do
  930. // process rundown for kernel trace.
  931. //
  932. if (ErrorCode == ERROR_SUCCESS) {
  933. ErrorCode = EtwpFinalizeLogFileHeader(LoggerInfo);
  934. }
  935. }
  936. return EtwpSetDosError(ErrorCode);
  937. }
  938. ULONG
  939. EtwpQueryLogger(
  940. IN OUT PWMI_LOGGER_INFORMATION LoggerInfo,
  941. IN ULONG Update
  942. )
  943. /*++
  944. Routine Description:
  945. This is the actual routine to communicate with the kernel to query
  946. the logger. All the properties of the logger will be returned in LoggerInfo.
  947. Arguments:
  948. LoggerInfo The actual parameters to be passed to and return from
  949. kernel.
  950. Return Value:
  951. The status of performing the action requested.
  952. --*/
  953. {
  954. ULONG Status, ReturnSize;
  955. HANDLE LogFileHandle = NULL;
  956. PTRACE_ENABLE_CONTEXT pContext;
  957. BOOLEAN bAddAppendFlag = FALSE;
  958. ULONG SavedLogFileMode;
  959. ULONG IsPrivate;
  960. LoggerInfo->Checksum = NULL;
  961. LoggerInfo->LogFileHandle = NULL;
  962. pContext = (PTRACE_ENABLE_CONTEXT) &LoggerInfo->Wnode.HistoricalContext;
  963. IsPrivate = (LoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE)
  964. || (pContext->InternalFlag & EVENT_TRACE_INTERNAL_FLAG_PRIVATE);
  965. //
  966. // If UPDATE and a new logfile is given throw in the LogFileHeader
  967. //
  968. if ( Update && LoggerInfo->LogFileName.Length > 0) {
  969. if ( ! IsPrivate) {
  970. Status = EtwpAddLogHeaderToLogFile(LoggerInfo, NULL, Update);
  971. if (Status != ERROR_SUCCESS) {
  972. return EtwpSetDosError(Status);
  973. }
  974. LogFileHandle = LoggerInfo->LogFileHandle;
  975. bAddAppendFlag = TRUE;
  976. //
  977. // If we are switching to a new file, make sure it is append mode
  978. //
  979. SavedLogFileMode = LoggerInfo->LogFileMode;
  980. }
  981. }
  982. if (IsPrivate) {
  983. Status = EtwpSendUmLogRequest(
  984. (Update) ? (WmiUpdateLoggerCode) : (WmiQueryLoggerCode),
  985. LoggerInfo
  986. );
  987. }
  988. else {
  989. Status = EtwpSendWmiKMRequest(
  990. NULL,
  991. (Update ? IOCTL_WMI_UPDATE_LOGGER : IOCTL_WMI_QUERY_LOGGER),
  992. LoggerInfo,
  993. LoggerInfo->Wnode.BufferSize,
  994. LoggerInfo,
  995. LoggerInfo->Wnode.BufferSize,
  996. &ReturnSize,
  997. NULL
  998. );
  999. // Close the handle if it's not NULL
  1000. if (LoggerInfo->LogFileHandle != NULL) {
  1001. NtClose(LoggerInfo->LogFileHandle);
  1002. LoggerInfo->LogFileHandle = NULL;
  1003. }
  1004. if (Update && Status != ERROR_SUCCESS) {
  1005. if (LoggerInfo->LogFileName.Buffer != NULL) {
  1006. EtwpDeleteFileW(LoggerInfo->LogFileName.Buffer);
  1007. }
  1008. }
  1009. if (LoggerInfo->Checksum != NULL) {
  1010. EtwpFree(LoggerInfo->Checksum);
  1011. }
  1012. }
  1013. if (bAddAppendFlag) {
  1014. LoggerInfo->LogFileMode = SavedLogFileMode;
  1015. }
  1016. return EtwpSetDosError(Status);
  1017. }
  1018. PVOID
  1019. EtwpGetTraceBuffer(
  1020. IN PWMI_LOGGER_CONTEXT Logger,
  1021. IN PSYSTEM_THREAD_INFORMATION pThread,
  1022. IN ULONG GroupType,
  1023. IN ULONG RequiredSize
  1024. )
  1025. {
  1026. PSYSTEM_TRACE_HEADER Header;
  1027. PWMI_BUFFER_HEADER Buffer;
  1028. THREAD_BASIC_INFORMATION ThreadInfo;
  1029. KERNEL_USER_TIMES ThreadCpu;
  1030. NTSTATUS Status;
  1031. ULONG BytesUsed;
  1032. PCLIENT_ID Cid;
  1033. RequiredSize += sizeof (SYSTEM_TRACE_HEADER); // add in header
  1034. RequiredSize = (ULONG) ALIGN_TO_POWER2(RequiredSize, WmiTraceAlignment);
  1035. Buffer = (PWMI_BUFFER_HEADER) Logger->BufferSpace;
  1036. if (RequiredSize > Logger->BufferSize - sizeof(WMI_BUFFER_HEADER)) {
  1037. EtwpSetDosError(ERROR_BUFFER_OVERFLOW);
  1038. return NULL;
  1039. }
  1040. if (RequiredSize > (Logger->BufferSize - Buffer->Offset)) {
  1041. IO_STATUS_BLOCK IoStatus;
  1042. if (Buffer->Offset < Logger->BufferSize) {
  1043. RtlFillMemory(
  1044. (char *) Buffer + Buffer->Offset,
  1045. Logger->BufferSize - Buffer->Offset,
  1046. 0xFF);
  1047. }
  1048. Buffer->BufferType = WMI_BUFFER_TYPE_RUNDOWN;
  1049. Buffer->BufferFlag = WMI_BUFFER_FLAG_FLUSH_MARKER;
  1050. Status = NtWriteFile(
  1051. Logger->LogFileHandle,
  1052. NULL,
  1053. NULL,
  1054. NULL,
  1055. &IoStatus,
  1056. Buffer,
  1057. Logger->BufferSize,
  1058. NULL,
  1059. NULL);
  1060. Buffer->Offset = sizeof(WMI_BUFFER_HEADER);
  1061. if (!NT_SUCCESS(Status)) {
  1062. return NULL;
  1063. }
  1064. Logger->BuffersWritten++;
  1065. }
  1066. Header = (PSYSTEM_TRACE_HEADER) ((char*)Buffer + Buffer->Offset);
  1067. if (Logger->UsePerfClock == EVENT_TRACE_CLOCK_PERFCOUNTER) {
  1068. LARGE_INTEGER Frequency;
  1069. ULONGLONG Counter = 0;
  1070. Status = NtQueryPerformanceCounter((PLARGE_INTEGER)&Counter,
  1071. &Frequency);
  1072. Header->SystemTime.QuadPart = Counter;
  1073. } else if (Logger->UsePerfClock == EVENT_TRACE_CLOCK_CPUCYCLE) {
  1074. Header->SystemTime.QuadPart = EtwpGetCycleCount();
  1075. } else {
  1076. Header->SystemTime.QuadPart = EtwpGetSystemTime();
  1077. }
  1078. Header->Header = (GroupType << 16) + RequiredSize;
  1079. Header->Marker = SYSTEM_TRACE_MARKER;
  1080. if (pThread == NULL) {
  1081. Status = NtQueryInformationThread(
  1082. NtCurrentThread(),
  1083. ThreadBasicInformation,
  1084. &ThreadInfo,
  1085. sizeof ThreadInfo, NULL);
  1086. if (NT_SUCCESS(Status)) {
  1087. Cid = &ThreadInfo.ClientId;
  1088. Header->ThreadId = HandleToUlong(Cid->UniqueThread);
  1089. Header->ProcessId = HandleToUlong(Cid->UniqueProcess);
  1090. }
  1091. Status = NtQueryInformationThread(
  1092. NtCurrentThread(),
  1093. ThreadTimes,
  1094. &ThreadCpu, sizeof ThreadCpu, NULL);
  1095. if (NT_SUCCESS(Status)) {
  1096. Header->KernelTime = (ULONG) (ThreadCpu.KernelTime.QuadPart
  1097. / Logger->TimerResolution);
  1098. Header->UserTime = (ULONG) (ThreadCpu.UserTime.QuadPart
  1099. / Logger->TimerResolution);
  1100. }
  1101. }
  1102. else {
  1103. Cid = &pThread->ClientId;
  1104. Header->ThreadId = HandleToUlong(Cid->UniqueThread);
  1105. Header->ProcessId = HandleToUlong(Cid->UniqueProcess);
  1106. Header->KernelTime = (ULONG) (pThread->KernelTime.QuadPart
  1107. / Logger->TimerResolution);
  1108. Header->UserTime = (ULONG) (pThread->UserTime.QuadPart
  1109. / Logger->TimerResolution);
  1110. }
  1111. Buffer->Offset += RequiredSize;
  1112. // If there is room, throw in a end of buffer marker.
  1113. BytesUsed = Buffer->Offset;
  1114. if ( BytesUsed <= (Logger->BufferSize-sizeof(ULONG)) ) {
  1115. *((long*)((char*)Buffer+Buffer->Offset)) = -1;
  1116. }
  1117. return (PVOID) ( (char*) Header + sizeof(SYSTEM_TRACE_HEADER) );
  1118. }
  1119. VOID
  1120. EtwpCopyPropertiesToInfo(
  1121. IN PEVENT_TRACE_PROPERTIES Properties,
  1122. IN PWMI_LOGGER_INFORMATION Info
  1123. )
  1124. {
  1125. ULONG SavedBufferSize = Info->Wnode.BufferSize;
  1126. RtlCopyMemory(&Info->Wnode, &Properties->Wnode, sizeof(WNODE_HEADER));
  1127. Info->Wnode.BufferSize = SavedBufferSize;
  1128. Info->BufferSize = Properties->BufferSize;
  1129. Info->MinimumBuffers = Properties->MinimumBuffers;
  1130. Info->MaximumBuffers = Properties->MaximumBuffers;
  1131. Info->NumberOfBuffers = Properties->NumberOfBuffers;
  1132. Info->FreeBuffers = Properties->FreeBuffers;
  1133. Info->EventsLost = Properties->EventsLost;
  1134. Info->BuffersWritten = Properties->BuffersWritten;
  1135. Info->LoggerThreadId = Properties->LoggerThreadId;
  1136. Info->MaximumFileSize = Properties->MaximumFileSize;
  1137. Info->EnableFlags = Properties->EnableFlags;
  1138. Info->LogFileMode = Properties->LogFileMode;
  1139. Info->FlushTimer = Properties->FlushTimer;
  1140. Info->LogBuffersLost = Properties->LogBuffersLost;
  1141. Info->AgeLimit = Properties->AgeLimit;
  1142. Info->RealTimeBuffersLost = Properties->RealTimeBuffersLost;
  1143. }
  1144. VOID
  1145. EtwpCopyInfoToProperties(
  1146. IN PWMI_LOGGER_INFORMATION Info,
  1147. IN PEVENT_TRACE_PROPERTIES Properties
  1148. )
  1149. {
  1150. ULONG SavedSize = Properties->Wnode.BufferSize;
  1151. RtlCopyMemory(&Properties->Wnode, &Info->Wnode, sizeof(WNODE_HEADER));
  1152. Properties->Wnode.BufferSize = SavedSize;
  1153. Properties->BufferSize = Info->BufferSize;
  1154. Properties->MinimumBuffers = Info->MinimumBuffers;
  1155. Properties->MaximumBuffers = Info->MaximumBuffers;
  1156. Properties->NumberOfBuffers = Info->NumberOfBuffers;
  1157. Properties->FreeBuffers = Info->FreeBuffers;
  1158. Properties->EventsLost = Info->EventsLost;
  1159. Properties->BuffersWritten = Info->BuffersWritten;
  1160. Properties->LoggerThreadId = Info->LoggerThreadId;
  1161. Properties->MaximumFileSize = Info->MaximumFileSize;
  1162. Properties->EnableFlags = Info->EnableFlags;
  1163. Properties->LogFileMode = Info->LogFileMode;
  1164. Properties->FlushTimer = Info->FlushTimer;
  1165. Properties->LogBuffersLost = Info->LogBuffersLost;
  1166. Properties->AgeLimit = Info->AgeLimit;
  1167. Properties->RealTimeBuffersLost = Info->RealTimeBuffersLost;
  1168. }
  1169. NTSTATUS
  1170. EtwpThreadRunDown(
  1171. IN PWMI_LOGGER_CONTEXT Logger,
  1172. IN PSYSTEM_PROCESS_INFORMATION pProcessInfo,
  1173. IN ULONG StartFlag,
  1174. IN BOOLEAN bExtended
  1175. )
  1176. {
  1177. PSYSTEM_THREAD_INFORMATION pThreadInfo;
  1178. ULONG GroupType;
  1179. ULONG i;
  1180. ULONG Size;
  1181. ULONG SystemThreadInfoSize;
  1182. PWMI_EXTENDED_THREAD_INFORMATION ThreadInfo;
  1183. PWMI_EXTENDED_THREAD_INFORMATION64 ThreadInfo64;
  1184. pThreadInfo = (PSYSTEM_THREAD_INFORMATION) (pProcessInfo+1);
  1185. GroupType = EVENT_TRACE_GROUP_THREAD +
  1186. ((StartFlag) ? EVENT_TRACE_TYPE_DC_START
  1187. : EVENT_TRACE_TYPE_DC_END);
  1188. if (!KernelWow64) { // normal case
  1189. Size = sizeof(WMI_EXTENDED_THREAD_INFORMATION);
  1190. SystemThreadInfoSize = (bExtended)
  1191. ? sizeof(SYSTEM_EXTENDED_THREAD_INFORMATION)
  1192. : sizeof(SYSTEM_THREAD_INFORMATION);
  1193. for (i=0; i < pProcessInfo->NumberOfThreads; i++) {
  1194. if (pThreadInfo == NULL)
  1195. break;
  1196. ThreadInfo = (PWMI_EXTENDED_THREAD_INFORMATION)
  1197. EtwpGetTraceBuffer( Logger,
  1198. pThreadInfo,
  1199. GroupType,
  1200. Size );
  1201. if (ThreadInfo) {
  1202. ThreadInfo->ProcessId =
  1203. HandleToUlong(pThreadInfo->ClientId.UniqueProcess);
  1204. ThreadInfo->ThreadId =
  1205. HandleToUlong(pThreadInfo->ClientId.UniqueThread);
  1206. if (bExtended) {
  1207. PSYSTEM_EXTENDED_THREAD_INFORMATION pExtThreadInfo;
  1208. pExtThreadInfo = (PSYSTEM_EXTENDED_THREAD_INFORMATION)
  1209. pThreadInfo;
  1210. ThreadInfo->StackBase = pExtThreadInfo->StackBase;
  1211. ThreadInfo->StackLimit = pExtThreadInfo->StackLimit;
  1212. ThreadInfo->StartAddr =
  1213. pExtThreadInfo->ThreadInfo.StartAddress;
  1214. ThreadInfo->Win32StartAddr =
  1215. pExtThreadInfo->Win32StartAddress;
  1216. ThreadInfo->UserStackBase = 0;
  1217. ThreadInfo->UserStackLimit = 0;
  1218. ThreadInfo->WaitMode = -1;
  1219. }
  1220. else {
  1221. ThreadInfo->StackBase = 0;
  1222. ThreadInfo->StackLimit = 0;
  1223. ThreadInfo->StartAddr = 0;
  1224. ThreadInfo->Win32StartAddr = 0;
  1225. ThreadInfo->UserStackBase = 0;
  1226. ThreadInfo->UserStackLimit = 0;
  1227. ThreadInfo->WaitMode = -1;
  1228. }
  1229. }
  1230. pThreadInfo = (PSYSTEM_THREAD_INFORMATION)
  1231. ( (char*)pThreadInfo +SystemThreadInfoSize );
  1232. }
  1233. }
  1234. else { // KernelWow64
  1235. Size = sizeof(WMI_EXTENDED_THREAD_INFORMATION64);
  1236. SystemThreadInfoSize = (bExtended)
  1237. ? sizeof(SYSTEM_EXTENDED_THREAD_INFORMATION)
  1238. : sizeof(SYSTEM_THREAD_INFORMATION);
  1239. for (i=0; i < pProcessInfo->NumberOfThreads; i++) {
  1240. if (pThreadInfo == NULL)
  1241. break;
  1242. ThreadInfo64 = (PWMI_EXTENDED_THREAD_INFORMATION64)
  1243. EtwpGetTraceBuffer( Logger,
  1244. pThreadInfo,
  1245. GroupType,
  1246. Size );
  1247. if (ThreadInfo64) {
  1248. ThreadInfo64->ProcessId =
  1249. HandleToUlong(pThreadInfo->ClientId.UniqueProcess);
  1250. ThreadInfo64->ThreadId =
  1251. HandleToUlong(pThreadInfo->ClientId.UniqueThread);
  1252. if (bExtended) {
  1253. PSYSTEM_EXTENDED_THREAD_INFORMATION pExtThreadInfo;
  1254. pExtThreadInfo =
  1255. (PSYSTEM_EXTENDED_THREAD_INFORMATION) pThreadInfo;
  1256. ThreadInfo64->StackBase64 = 0;
  1257. ThreadInfo64->StackBase64 =
  1258. (ULONG64)(pExtThreadInfo->StackBase);
  1259. ThreadInfo64->StackLimit64 = 0;
  1260. ThreadInfo64->StackLimit64 =
  1261. (ULONG64)(pExtThreadInfo->StackLimit);
  1262. ThreadInfo64->StartAddr64 = 0;
  1263. ThreadInfo64->StartAddr64 =
  1264. (ULONG64)(pExtThreadInfo->ThreadInfo.StartAddress);
  1265. ThreadInfo64->Win32StartAddr64 = 0;
  1266. ThreadInfo64->Win32StartAddr64 =
  1267. (ULONG64)(pExtThreadInfo->Win32StartAddress);
  1268. ThreadInfo64->UserStackBase64 = 0;
  1269. ThreadInfo64->UserStackLimit64 = 0;
  1270. ThreadInfo64->WaitMode = -1;
  1271. }
  1272. else {
  1273. ThreadInfo64->StackBase64 = 0;
  1274. ThreadInfo64->StackLimit64 = 0;
  1275. ThreadInfo64->StartAddr64 = 0;
  1276. ThreadInfo64->Win32StartAddr64 = 0;
  1277. ThreadInfo64->UserStackBase64 = 0;
  1278. ThreadInfo64->UserStackLimit64 = 0;
  1279. ThreadInfo64->WaitMode = -1;
  1280. }
  1281. }
  1282. pThreadInfo = (PSYSTEM_THREAD_INFORMATION)
  1283. ( (char*)pThreadInfo + SystemThreadInfoSize );
  1284. }
  1285. }
  1286. return STATUS_SUCCESS;
  1287. }
  1288. void
  1289. EtwpLogImageLoadEvent(
  1290. IN HANDLE ProcessID,
  1291. IN PWMI_LOGGER_CONTEXT pLogger,
  1292. IN PRTL_PROCESS_MODULE_INFORMATION pModuleInfo,
  1293. IN PSYSTEM_THREAD_INFORMATION pThreadInfo
  1294. )
  1295. {
  1296. UNICODE_STRING wstrModuleName;
  1297. ANSI_STRING astrModuleName;
  1298. ULONG sizeModuleName;
  1299. ULONG sizeBuffer;
  1300. PCHAR pAuxInfo;
  1301. PWMI_IMAGELOAD_INFORMATION ImageLoadInfo;
  1302. PWMI_IMAGELOAD_INFORMATION64 ImageLoadInfo64;
  1303. if ((pLogger == NULL) || (pModuleInfo == NULL) || (pThreadInfo == NULL))
  1304. return;
  1305. RtlInitAnsiString( & astrModuleName, pModuleInfo->FullPathName);
  1306. sizeModuleName = sizeof(WCHAR) * (astrModuleName.Length);
  1307. if (!KernelWow64) { // normal case
  1308. sizeBuffer = sizeModuleName + sizeof(WCHAR)
  1309. + FIELD_OFFSET (WMI_IMAGELOAD_INFORMATION, FileName);
  1310. ImageLoadInfo = (PWMI_IMAGELOAD_INFORMATION)
  1311. EtwpGetTraceBuffer(
  1312. pLogger,
  1313. pThreadInfo,
  1314. EVENT_TRACE_GROUP_PROCESS + EVENT_TRACE_TYPE_LOAD,
  1315. sizeBuffer);
  1316. if (ImageLoadInfo == NULL) {
  1317. return;
  1318. }
  1319. ImageLoadInfo->ImageBase = pModuleInfo->ImageBase;
  1320. ImageLoadInfo->ImageSize = pModuleInfo->ImageSize;
  1321. ImageLoadInfo->ProcessId = HandleToUlong(ProcessID);
  1322. wstrModuleName.Buffer = (LPWSTR) &ImageLoadInfo->FileName[0];
  1323. wstrModuleName.MaximumLength = (USHORT) sizeModuleName + sizeof(WCHAR);
  1324. RtlAnsiStringToUnicodeString(& wstrModuleName, & astrModuleName, FALSE);
  1325. }
  1326. else { // KernelWow64
  1327. sizeBuffer = sizeModuleName + sizeof(WCHAR)
  1328. + FIELD_OFFSET (WMI_IMAGELOAD_INFORMATION64, FileName);
  1329. ImageLoadInfo64 = (PWMI_IMAGELOAD_INFORMATION64)
  1330. EtwpGetTraceBuffer(
  1331. pLogger,
  1332. pThreadInfo,
  1333. EVENT_TRACE_GROUP_PROCESS + EVENT_TRACE_TYPE_LOAD,
  1334. sizeBuffer);
  1335. if (ImageLoadInfo64 == NULL) {
  1336. return;
  1337. }
  1338. ImageLoadInfo64->ImageBase64 = 0;
  1339. ImageLoadInfo64->ImageBase64 = (ULONG64)(pModuleInfo->ImageBase);
  1340. ImageLoadInfo64->ImageSize64 = 0;
  1341. ImageLoadInfo64->ImageSize64 = (ULONG64)(pModuleInfo->ImageSize);
  1342. ImageLoadInfo64->ProcessId = HandleToUlong(ProcessID);
  1343. wstrModuleName.Buffer = (LPWSTR) &ImageLoadInfo64->FileName[0];
  1344. wstrModuleName.MaximumLength = (USHORT) sizeModuleName + sizeof(WCHAR);
  1345. RtlAnsiStringToUnicodeString(& wstrModuleName, & astrModuleName, FALSE);
  1346. }
  1347. }
  1348. ULONG
  1349. EtwpSysModuleRunDown(
  1350. IN PWMI_LOGGER_CONTEXT pLogger,
  1351. IN PSYSTEM_THREAD_INFORMATION pThreadInfo
  1352. )
  1353. {
  1354. NTSTATUS status = STATUS_SUCCESS;
  1355. char * pLargeBuffer1;
  1356. ULONG ReturnLength;
  1357. ULONG CurrentBufferSize;
  1358. ULONG i;
  1359. PRTL_PROCESS_MODULES pModules;
  1360. PRTL_PROCESS_MODULE_INFORMATION pModuleInfo;
  1361. pLargeBuffer1 = EtwpMemReserve(MAX_BUFFER_SIZE);
  1362. if (pLargeBuffer1 == NULL)
  1363. {
  1364. status = STATUS_NO_MEMORY;
  1365. goto Cleanup;
  1366. }
  1367. if (EtwpMemCommit(pLargeBuffer1, BUFFER_SIZE) == NULL)
  1368. {
  1369. status = STATUS_NO_MEMORY;
  1370. goto Cleanup;
  1371. }
  1372. CurrentBufferSize = BUFFER_SIZE;
  1373. retry:
  1374. status = NtQuerySystemInformation(
  1375. SystemModuleInformation,
  1376. pLargeBuffer1,
  1377. CurrentBufferSize,
  1378. &ReturnLength);
  1379. if (status == STATUS_INFO_LENGTH_MISMATCH)
  1380. {
  1381. // Increase buffer size. ReturnLength shows how much we need. Add
  1382. // another 4K buffer for additional modules loaded since this call.
  1383. //
  1384. if (CurrentBufferSize < ReturnLength) {
  1385. CurrentBufferSize = ReturnLength;
  1386. }
  1387. CurrentBufferSize = PAGESIZE_MULTIPLE(CurrentBufferSize + SMALL_BUFFER_SIZE);
  1388. if (EtwpMemCommit(pLargeBuffer1, CurrentBufferSize) == NULL)
  1389. {
  1390. status = STATUS_NO_MEMORY;
  1391. goto Cleanup;
  1392. }
  1393. goto retry;
  1394. }
  1395. if (!NT_SUCCESS(status))
  1396. {
  1397. goto Cleanup;
  1398. }
  1399. pModules = (PRTL_PROCESS_MODULES) pLargeBuffer1;
  1400. for (i = 0, pModuleInfo = & (pModules->Modules[0]);
  1401. i < pModules->NumberOfModules;
  1402. i ++, pModuleInfo ++)
  1403. {
  1404. EtwpLogImageLoadEvent(NULL, pLogger, pModuleInfo, pThreadInfo);
  1405. }
  1406. Cleanup:
  1407. if (pLargeBuffer1)
  1408. {
  1409. EtwpMemFree(pLargeBuffer1);
  1410. }
  1411. return EtwpSetDosError(EtwpNtStatusToDosError(status));
  1412. }
  1413. ULONG
  1414. EtwpProcessModuleRunDown(
  1415. IN PWMI_LOGGER_CONTEXT pLogger,
  1416. IN HANDLE ProcessID,
  1417. IN PSYSTEM_THREAD_INFORMATION pThreadInfo)
  1418. {
  1419. NTSTATUS status = STATUS_SUCCESS;
  1420. ULONG i;
  1421. PRTL_DEBUG_INFORMATION pLargeBuffer1 = NULL;
  1422. pLargeBuffer1 = RtlCreateQueryDebugBuffer(0, FALSE);
  1423. if (pLargeBuffer1 == NULL)
  1424. {
  1425. status = STATUS_NO_MEMORY;
  1426. goto Cleanup;
  1427. }
  1428. status = RtlQueryProcessDebugInformation(
  1429. ProcessID,
  1430. RTL_QUERY_PROCESS_NONINVASIVE | RTL_QUERY_PROCESS_MODULES,
  1431. pLargeBuffer1);
  1432. if ( !NT_SUCCESS(status) || (pLargeBuffer1->Modules == NULL) )
  1433. {
  1434. goto Cleanup;
  1435. }
  1436. //
  1437. // RtlQueryProcessDebugInformation call is returning a buffer from an
  1438. // untrusted source with pointers and offset and it isn't validating it.
  1439. // Therefore we can not assume that this buffer is trustworthy.
  1440. // Since we elevated our privilege to SE_DEBUG_PRIVILEGE we need a
  1441. // condition handler here to exit cleanly and reset the privilege.
  1442. //
  1443. //
  1444. try {
  1445. for (i = 0; i < pLargeBuffer1->Modules->NumberOfModules; i ++)
  1446. {
  1447. EtwpLogImageLoadEvent(
  1448. ProcessID,
  1449. pLogger,
  1450. & (pLargeBuffer1->Modules->Modules[i]),
  1451. pThreadInfo);
  1452. }
  1453. }
  1454. except (EXCEPTION_EXECUTE_HANDLER) {
  1455. status = ERROR_NOACCESS;
  1456. }
  1457. Cleanup:
  1458. if (pLargeBuffer1)
  1459. {
  1460. RtlDestroyQueryDebugBuffer(pLargeBuffer1);
  1461. }
  1462. return EtwpSetDosError(EtwpNtStatusToDosError(status));
  1463. }
  1464. NTSTATUS
  1465. EtwpProcessRunDown(
  1466. IN PWMI_LOGGER_CONTEXT Logger,
  1467. IN ULONG StartFlag,
  1468. IN ULONG fEnableFlags
  1469. )
  1470. {
  1471. PSYSTEM_PROCESS_INFORMATION pProcessInfo;
  1472. PSYSTEM_THREAD_INFORMATION pThreadInfo;
  1473. char* LargeBuffer1;
  1474. NTSTATUS status;
  1475. ULONG ReturnLength;
  1476. ULONG CurrentBufferSize;
  1477. ULONG GroupType;
  1478. ULONG TotalOffset = 0;
  1479. OBJECT_ATTRIBUTES objectAttributes;
  1480. BOOLEAN WasEnabled = TRUE;
  1481. BOOLEAN bExtended = TRUE;
  1482. LargeBuffer1 = EtwpMemReserve ( MAX_BUFFER_SIZE );
  1483. if (LargeBuffer1 == NULL) {
  1484. return STATUS_NO_MEMORY;
  1485. }
  1486. if (EtwpMemCommit (LargeBuffer1, BUFFER_SIZE) == NULL) {
  1487. return STATUS_NO_MEMORY;
  1488. }
  1489. CurrentBufferSize = BUFFER_SIZE;
  1490. retry:
  1491. if (bExtended) {
  1492. status = NtQuerySystemInformation(
  1493. SystemExtendedProcessInformation,
  1494. LargeBuffer1,
  1495. CurrentBufferSize,
  1496. &ReturnLength
  1497. );
  1498. }
  1499. else {
  1500. status = NtQuerySystemInformation(
  1501. SystemProcessInformation,
  1502. LargeBuffer1,
  1503. CurrentBufferSize,
  1504. &ReturnLength
  1505. );
  1506. }
  1507. if (status == STATUS_INFO_LENGTH_MISMATCH) {
  1508. //
  1509. // Increase buffer size.
  1510. //
  1511. if (CurrentBufferSize < ReturnLength) {
  1512. CurrentBufferSize = ReturnLength;
  1513. }
  1514. CurrentBufferSize =
  1515. PAGESIZE_MULTIPLE(CurrentBufferSize + SMALL_BUFFER_SIZE);
  1516. if (EtwpMemCommit (LargeBuffer1, CurrentBufferSize) == NULL) {
  1517. return STATUS_NO_MEMORY;
  1518. }
  1519. goto retry;
  1520. }
  1521. if (!NT_SUCCESS(status)) {
  1522. if (bExtended) {
  1523. bExtended = FALSE;
  1524. goto retry;
  1525. }
  1526. EtwpMemFree(LargeBuffer1);
  1527. return(status);
  1528. }
  1529. //
  1530. // Adjust Privileges to obtain the module information
  1531. //
  1532. if (fEnableFlags & EVENT_TRACE_FLAG_IMAGE_LOAD) {
  1533. status = RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE,
  1534. TRUE, FALSE, &WasEnabled);
  1535. if (!NT_SUCCESS(status)) {
  1536. status = RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE,
  1537. TRUE, TRUE, &WasEnabled);
  1538. }
  1539. if (!NT_SUCCESS(status)) {
  1540. EtwpMemFree(LargeBuffer1);
  1541. return (status);
  1542. }
  1543. }
  1544. TotalOffset = 0;
  1545. pProcessInfo = (SYSTEM_PROCESS_INFORMATION *) LargeBuffer1;
  1546. while (TRUE) {
  1547. ULONG Size;
  1548. ULONG Length = 0;
  1549. ULONG SidLength = 0;
  1550. PUCHAR AuxPtr;
  1551. PULONG_PTR AuxInfo;
  1552. ANSI_STRING s;
  1553. HANDLE Token;
  1554. HANDLE pProcess;
  1555. PCLIENT_ID Cid;
  1556. ULONG TempInfo[128];
  1557. PWMI_PROCESS_INFORMATION WmiProcessInfo;
  1558. PWMI_PROCESS_INFORMATION64 WmiProcessInfo64;
  1559. GroupType = EVENT_TRACE_GROUP_PROCESS +
  1560. ((StartFlag) ? EVENT_TRACE_TYPE_DC_START
  1561. : EVENT_TRACE_TYPE_DC_END);
  1562. pThreadInfo = (PSYSTEM_THREAD_INFORMATION) (pProcessInfo+1);
  1563. if (pProcessInfo->NumberOfThreads > 0) {
  1564. Cid = (PCLIENT_ID) &pThreadInfo->ClientId;
  1565. }
  1566. else {
  1567. Cid = NULL;
  1568. }
  1569. // if at termination, rundown thread first before process
  1570. if ( (!StartFlag) &&
  1571. (fEnableFlags & EVENT_TRACE_FLAG_THREAD) ){
  1572. status = EtwpThreadRunDown(Logger,
  1573. pProcessInfo,
  1574. StartFlag,
  1575. bExtended);
  1576. if (!NT_SUCCESS(status)) {
  1577. break;
  1578. }
  1579. }
  1580. if (fEnableFlags & EVENT_TRACE_FLAG_PROCESS) {
  1581. Length = 1;
  1582. if ( pProcessInfo->ImageName.Buffer &&
  1583. pProcessInfo->ImageName.Length > 0 ) {
  1584. status = RtlUnicodeStringToAnsiString(
  1585. &s,
  1586. (PUNICODE_STRING)&pProcessInfo->ImageName,
  1587. TRUE);
  1588. if (NT_SUCCESS(status)) {
  1589. Length = s.Length + 1;
  1590. }
  1591. }
  1592. InitializeObjectAttributes(
  1593. &objectAttributes, 0, 0, NULL, NULL);
  1594. status = NtOpenProcess(
  1595. &pProcess,
  1596. PROCESS_QUERY_INFORMATION,
  1597. &objectAttributes,
  1598. Cid);
  1599. if (NT_SUCCESS(status)) {
  1600. status = NtOpenProcessToken(
  1601. pProcess,
  1602. TOKEN_READ,
  1603. &Token);
  1604. if (NT_SUCCESS(status)) {
  1605. status = NtQueryInformationToken(
  1606. Token,
  1607. TokenUser,
  1608. TempInfo,
  1609. 256,
  1610. &SidLength);
  1611. NtClose(Token);
  1612. }
  1613. NtClose(pProcess);
  1614. }
  1615. if ( (!NT_SUCCESS(status)) || SidLength <= 0) {
  1616. TempInfo[0] = 0;
  1617. SidLength = sizeof(ULONG);
  1618. }
  1619. if (!KernelWow64) { // normal case
  1620. Size = FIELD_OFFSET(WMI_PROCESS_INFORMATION, Sid);
  1621. Size += Length + SidLength;
  1622. WmiProcessInfo = (PWMI_PROCESS_INFORMATION)
  1623. EtwpGetTraceBuffer( Logger,
  1624. pThreadInfo,
  1625. GroupType,
  1626. Size);
  1627. if (WmiProcessInfo == NULL) {
  1628. status = STATUS_NO_MEMORY;
  1629. break;
  1630. }
  1631. WmiProcessInfo->ProcessId =
  1632. HandleToUlong( pProcessInfo->UniqueProcessId);
  1633. WmiProcessInfo->ParentId =
  1634. HandleToUlong( pProcessInfo->InheritedFromUniqueProcessId);
  1635. WmiProcessInfo->SessionId = pProcessInfo->SessionId;
  1636. WmiProcessInfo->PageDirectoryBase =
  1637. pProcessInfo->PageDirectoryBase;
  1638. WmiProcessInfo->ExitStatus = 0;
  1639. AuxPtr = (PUCHAR) (&WmiProcessInfo->Sid);
  1640. RtlCopyMemory(AuxPtr, &TempInfo[0], SidLength);
  1641. AuxPtr += SidLength;
  1642. if (Length > 1) {
  1643. RtlCopyMemory(AuxPtr, s.Buffer, Length - 1);
  1644. AuxPtr += (Length - 1);
  1645. RtlFreeAnsiString(&s);
  1646. }
  1647. *AuxPtr = '\0';
  1648. AuxPtr++;
  1649. }
  1650. else { // KernelWow64
  1651. Size = FIELD_OFFSET(WMI_PROCESS_INFORMATION64, Sid);
  1652. if (SidLength != sizeof(ULONG)) {
  1653. Size += Length + SidLength + 8;
  1654. }
  1655. else {
  1656. Size += Length + SidLength;
  1657. }
  1658. WmiProcessInfo64 = (PWMI_PROCESS_INFORMATION64)
  1659. EtwpGetTraceBuffer( Logger,
  1660. pThreadInfo,
  1661. GroupType,
  1662. Size);
  1663. if (WmiProcessInfo64 == NULL) {
  1664. status = STATUS_NO_MEMORY;
  1665. break;
  1666. }
  1667. WmiProcessInfo64->ProcessId =
  1668. HandleToUlong( pProcessInfo->UniqueProcessId);
  1669. WmiProcessInfo64->ParentId =
  1670. HandleToUlong( pProcessInfo->InheritedFromUniqueProcessId);
  1671. WmiProcessInfo64->SessionId = pProcessInfo->SessionId;
  1672. WmiProcessInfo64->PageDirectoryBase64 = 0;
  1673. WmiProcessInfo64->PageDirectoryBase64 =
  1674. (ULONG64)(pProcessInfo->PageDirectoryBase);
  1675. WmiProcessInfo64->ExitStatus = 0;
  1676. // We need to widen TOKEN_USER structure before copying SID.
  1677. // Technically, what follows is not the correct way to extend
  1678. // SID for Wow64. The correct way is to widen the pointer
  1679. // inside the TOKEN_USER structure within the returned SID blob.
  1680. // However, we don't really care what the pointer value is, we
  1681. // just need to know that it is not 0. Hence, we copy
  1682. // TOKEN_USER first, leave some space out, and we copy the
  1683. // actual SID.
  1684. AuxPtr = (PUCHAR) (&WmiProcessInfo64->Sid);
  1685. if (SidLength > 8) {
  1686. RtlCopyMemory(AuxPtr, &TempInfo[0], 8);
  1687. RtlCopyMemory((AuxPtr + 16), &(TempInfo[2]), SidLength - 8);
  1688. AuxPtr += SidLength + 8;
  1689. }
  1690. else if (SidLength == sizeof(ULONG)) {
  1691. RtlCopyMemory(AuxPtr, &TempInfo[0], SidLength);
  1692. AuxPtr += SidLength;
  1693. }
  1694. else { // This really cannot/should not happen.
  1695. RtlCopyMemory(AuxPtr, &TempInfo[0], SidLength);
  1696. AuxPtr += SidLength + 8;
  1697. }
  1698. if (Length > 1) {
  1699. RtlCopyMemory(AuxPtr, s.Buffer, Length - 1);
  1700. AuxPtr += (Length - 1);
  1701. RtlFreeAnsiString(&s);
  1702. }
  1703. *AuxPtr = '\0';
  1704. AuxPtr++;
  1705. }
  1706. }
  1707. // if at beginning, trace threads after process
  1708. if (StartFlag) {
  1709. if (fEnableFlags & EVENT_TRACE_FLAG_THREAD) {
  1710. EtwpThreadRunDown(Logger, pProcessInfo, StartFlag, bExtended);
  1711. }
  1712. if (fEnableFlags & EVENT_TRACE_FLAG_IMAGE_LOAD) {
  1713. if (pProcessInfo->UniqueProcessId == 0) {
  1714. EtwpSysModuleRunDown(Logger, pThreadInfo);
  1715. }
  1716. else
  1717. EtwpProcessModuleRunDown(
  1718. Logger,
  1719. (HANDLE) pProcessInfo->UniqueProcessId,
  1720. pThreadInfo);
  1721. }
  1722. }
  1723. if (pProcessInfo->NextEntryOffset == 0) {
  1724. break;
  1725. }
  1726. TotalOffset += pProcessInfo->NextEntryOffset;
  1727. pProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&LargeBuffer1[TotalOffset];
  1728. }
  1729. //
  1730. // Restore privileges back to what it was before
  1731. //
  1732. if ( (fEnableFlags & EVENT_TRACE_FLAG_IMAGE_LOAD) && WasEnabled ) {
  1733. status = RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE,
  1734. FALSE,
  1735. FALSE,
  1736. &WasEnabled);
  1737. if (!NT_SUCCESS(status)) {
  1738. status = RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE,
  1739. FALSE,
  1740. TRUE,
  1741. &WasEnabled);
  1742. }
  1743. }
  1744. EtwpMemFree(LargeBuffer1);
  1745. return status;
  1746. }
  1747. VOID
  1748. EtwpInitString(
  1749. IN PVOID Destination,
  1750. IN PVOID Buffer,
  1751. IN ULONG Size
  1752. )
  1753. {
  1754. PSTRING s = (PSTRING) Destination;
  1755. s->Buffer = Buffer;
  1756. s->Length = 0;
  1757. if (Buffer != NULL)
  1758. s->MaximumLength = (USHORT) Size;
  1759. else
  1760. s->MaximumLength = 0;
  1761. }
  1762. ULONG
  1763. EtwpRelogHeaderToLogFile(
  1764. IN OUT PWMI_LOGGER_INFORMATION LoggerInfo,
  1765. IN PSYSTEM_TRACE_HEADER RelogProp
  1766. )
  1767. {
  1768. PTRACE_LOGFILE_HEADER RelogFileHeader;
  1769. LPWSTR FileName = NULL;
  1770. ULONG RelogPropSize;
  1771. HANDLE LogFile = INVALID_HANDLE_VALUE;
  1772. ULONG BufferSize;
  1773. IO_STATUS_BLOCK IoStatus;
  1774. PWMI_BUFFER_HEADER Buffer;
  1775. LPWSTR FileNameBuffer = NULL;
  1776. PUCHAR BufferSpace;
  1777. NTSTATUS Status;
  1778. RelogFileHeader = (PTRACE_LOGFILE_HEADER) ((PUCHAR)RelogProp +
  1779. sizeof(SYSTEM_TRACE_HEADER) );
  1780. RelogPropSize = RelogProp->Packet.Size;
  1781. FileName = (LPWSTR) LoggerInfo->LogFileName.Buffer;
  1782. if (FileName == NULL) {
  1783. return EtwpSetDosError(ERROR_BAD_PATHNAME);
  1784. }
  1785. LogFile = EtwpCreateFileW(
  1786. FileName,
  1787. GENERIC_WRITE,
  1788. FILE_SHARE_READ,
  1789. NULL,
  1790. CREATE_ALWAYS,
  1791. FILE_ATTRIBUTE_NORMAL,
  1792. NULL);
  1793. if (LogFile == INVALID_HANDLE_VALUE) {
  1794. return EtwpGetLastError();
  1795. }
  1796. LoggerInfo->LogFileHandle = LogFile;
  1797. LoggerInfo->NumberOfProcessors = RelogFileHeader->NumberOfProcessors;
  1798. if (8 == RelogFileHeader->PointerSize && 4 == sizeof(PVOID)) {
  1799. LoggerInfo->Wnode.ClientContext =
  1800. *((PULONG)((PUCHAR)RelogFileHeader +
  1801. FIELD_OFFSET(TRACE_LOGFILE_HEADER, ReservedFlags) +
  1802. 8));
  1803. }
  1804. else if (4 == RelogFileHeader->PointerSize && 8 == sizeof(PVOID)) {
  1805. LoggerInfo->Wnode.ClientContext =
  1806. *((PULONG)((PUCHAR)RelogFileHeader +
  1807. FIELD_OFFSET(TRACE_LOGFILE_HEADER, ReservedFlags)
  1808. - 8));
  1809. }
  1810. else {
  1811. LoggerInfo->Wnode.ClientContext = RelogFileHeader->ReservedFlags;
  1812. }
  1813. BufferSize = LoggerInfo->BufferSize * 1024;
  1814. BufferSpace = EtwpAlloc(BufferSize);
  1815. if (BufferSpace == NULL) {
  1816. NtClose(LogFile);
  1817. return EtwpSetDosError(ERROR_NOT_ENOUGH_MEMORY);
  1818. }
  1819. // initialize buffer first
  1820. RtlZeroMemory(BufferSpace, BufferSize);
  1821. Buffer = (PWMI_BUFFER_HEADER) BufferSpace;
  1822. Buffer->Offset = sizeof(WMI_BUFFER_HEADER);
  1823. //
  1824. // We are making this an Application Trace always.
  1825. // However, if two application traces are relogged
  1826. // the Guidmaps are not really consolidated.
  1827. //
  1828. Buffer->Wnode.Guid = LoggerInfo->Wnode.Guid;
  1829. RelogFileHeader->LogFileMode = EVENT_TRACE_RELOG_MODE;
  1830. Buffer->Wnode.BufferSize = BufferSize;
  1831. Buffer->ClientContext.Alignment = (UCHAR)WmiTraceAlignment;
  1832. Buffer->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
  1833. RelogFileHeader->BuffersWritten = 1;
  1834. LoggerInfo->BuffersWritten = 1;
  1835. Buffer->Offset = sizeof(WMI_BUFFER_HEADER) + RelogPropSize;
  1836. //
  1837. // Copy the Old LogFileHeader
  1838. //
  1839. RtlCopyMemory((char*) Buffer + sizeof(WMI_BUFFER_HEADER),
  1840. RelogProp,
  1841. RelogPropSize
  1842. );
  1843. if (Buffer->Offset < BufferSize) {
  1844. RtlFillMemory(
  1845. (char *) Buffer + Buffer->Offset,
  1846. BufferSize - Buffer->Offset,
  1847. 0xFF);
  1848. }
  1849. Buffer->BufferType = WMI_BUFFER_TYPE_RUNDOWN;
  1850. Buffer->BufferFlag = WMI_BUFFER_FLAG_FLUSH_MARKER;
  1851. Status = NtWriteFile(
  1852. LogFile,
  1853. NULL,
  1854. NULL,
  1855. NULL,
  1856. &IoStatus,
  1857. BufferSpace,
  1858. BufferSize,
  1859. NULL,
  1860. NULL);
  1861. NtClose(LogFile);
  1862. LogFile = EtwpCreateFileW(
  1863. FileName,
  1864. GENERIC_WRITE,
  1865. FILE_SHARE_READ,
  1866. NULL,
  1867. OPEN_EXISTING,
  1868. FILE_FLAG_NO_BUFFERING,
  1869. NULL
  1870. );
  1871. EtwpFree(BufferSpace);
  1872. if (LogFile == INVALID_HANDLE_VALUE) {
  1873. return EtwpGetLastError();
  1874. }
  1875. LoggerInfo->LogFileHandle = LogFile;
  1876. return ERROR_SUCCESS;
  1877. }
  1878. ULONG
  1879. EtwpFixLogFileHeaderForWow64(
  1880. IN PWMI_LOGGER_INFORMATION LoggerInfo,
  1881. IN OUT PTRACE_LOGFILE_HEADER LogfileHeader
  1882. )
  1883. {
  1884. PUCHAR TempSpace = NULL;
  1885. PULONG64 Ulong64Ptr;
  1886. ULONG SizeNeeded = 0;
  1887. if (LoggerInfo == NULL || LogfileHeader == NULL) {
  1888. return ERROR_INVALID_PARAMETER;
  1889. }
  1890. SizeNeeded = sizeof(TRACE_LOGFILE_HEADER)
  1891. + LoggerInfo->LoggerName.Length + sizeof(WCHAR)
  1892. + LoggerInfo->LogFileName.Length + sizeof(WCHAR)
  1893. + 8;
  1894. TempSpace = EtwpAlloc(SizeNeeded);
  1895. if (TempSpace == NULL) {
  1896. return ERROR_NOT_ENOUGH_MEMORY;
  1897. }
  1898. RtlZeroMemory(TempSpace, SizeNeeded);
  1899. RtlCopyMemory(TempSpace, LogfileHeader, sizeof(TRACE_LOGFILE_HEADER));
  1900. Ulong64Ptr = (PULONG64)(TempSpace + FIELD_OFFSET(TRACE_LOGFILE_HEADER, LoggerName));
  1901. *Ulong64Ptr = (ULONG64)((PUCHAR)LogfileHeader + sizeof(TRACE_LOGFILE_HEADER) + 8);
  1902. RtlCopyMemory((TempSpace + sizeof(TRACE_LOGFILE_HEADER) + 8),
  1903. LogfileHeader->LoggerName,
  1904. LoggerInfo->LoggerName.Length + sizeof(WCHAR));
  1905. Ulong64Ptr++;
  1906. *Ulong64Ptr = (ULONG64)((PUCHAR)LogfileHeader + sizeof(TRACE_LOGFILE_HEADER)
  1907. + LoggerInfo->LoggerName.Length + sizeof(WCHAR) + 8);
  1908. RtlCopyMemory((TempSpace + sizeof(TRACE_LOGFILE_HEADER) + LoggerInfo->LoggerName.Length + sizeof(WCHAR) + 8),
  1909. LogfileHeader->LogFileName,
  1910. LoggerInfo->LogFileName.Length + sizeof(WCHAR));
  1911. Ulong64Ptr++;
  1912. RtlCopyMemory((PUCHAR)Ulong64Ptr, &(LogfileHeader->TimeZone),
  1913. sizeof(TRACE_LOGFILE_HEADER) - FIELD_OFFSET(TRACE_LOGFILE_HEADER, TimeZone));
  1914. RtlCopyMemory(LogfileHeader, TempSpace, SizeNeeded);
  1915. EtwpFree(TempSpace);
  1916. return ERROR_SUCCESS;
  1917. }
  1918. ULONG
  1919. EtwpAddLogHeaderToLogFile(
  1920. IN OUT PWMI_LOGGER_INFORMATION LoggerInfo,
  1921. IN PWMI_REF_CLOCK RefClock,
  1922. IN ULONG Update
  1923. )
  1924. /*++
  1925. Routine Description:
  1926. This routine creates a new log file header or updates an existing header
  1927. from an existing log file. StartTrace() and ControlTrace() will call this
  1928. routine to keep the log file header persistent.
  1929. Notes:
  1930. - Special cases should be considered carefully.
  1931. 1. Append case: The headers should be read from a file first, and
  1932. certain parameters specified by the user cannot be updated depending
  1933. on the value in the existing log file. In particular, the SystemTime
  1934. field in the header need to be updated accordingly.
  1935. 2. Update case: Similar to the case above. However, we do QueryTrace()
  1936. to get the latest info on the logging session instead of reading a
  1937. file header. Append and Update modes are mutually exclusive.
  1938. 3. Circular log file case: StartBuffers gets set to
  1939. LoggerInfo.BuffersWritten for correct post processing.
  1940. 4. Private logger case: LoggerInfo->Checksum is NULL if this is a
  1941. private logger.
  1942. 5. Prealloc log file case: This is the routine that extends the file
  1943. size. It happens at the end of the routine, just before closing and
  1944. opening the file for the second time.
  1945. 6. WOW64 case: Collecting kernel data under Wow64 is special in the
  1946. sense that kernel events will still have 64-bit pointer while some
  1947. user mode events (DCSTART and DCEND and Image events) will have
  1948. thunked pointers. For this reason, all events for kernel tracing on
  1949. ia64 machines will have 64-bit pointers and PointerSize will be
  1950. adjusted to 8 bytes if under Wow64.
  1951. 7. PrivateLogger: We should not call QueryLogger from this routine.
  1952. That will result in a deadlock since pump thread is executing
  1953. this code and it could block on the call waiting for itself
  1954. to respond.
  1955. - LogFile is a handle to a log file. When this routine returns with success
  1956. a handle to the logfile is open. If you call START or UPDATE ioctl
  1957. then it will be closed in the kernel (whether or not the call succeeds).
  1958. - Checksum, FileNameBuffer and Logger.BufferSpace are temporary spaces
  1959. allocated and used in this routine. Make sure they are freed before
  1960. all exits.
  1961. Arguments:
  1962. LoggerInfo Structure that keeps the information about a logger under
  1963. consideration. This will be properly updated. LogFileHandle
  1964. field will have a valid handle to a newly created log file.
  1965. RefClock Reference clock. The SystemTIme field in the header will be
  1966. updated accordingly. Used only in kernel trace.
  1967. Update Whether this is an update operation or not. Certain
  1968. parameters in the LoggerInfo (notably BufferSize) will not
  1969. be updated if this is TRUE.
  1970. Return Value:
  1971. The status of performing the action requested.
  1972. --*/
  1973. {
  1974. NTSTATUS Status;
  1975. HANDLE LogFile = INVALID_HANDLE_VALUE;
  1976. ULONG BufferSize;
  1977. ULONG MemorySize;
  1978. ULONG TraceKernel;
  1979. SYSTEM_BASIC_INFORMATION SystemInfo;
  1980. WMI_LOGGER_CONTEXT Logger;
  1981. IO_STATUS_BLOCK IoStatus;
  1982. PWMI_BUFFER_HEADER Buffer;
  1983. FILE_POSITION_INFORMATION FileInfo;
  1984. LPWSTR FileName = NULL;
  1985. LPWSTR FileNameBuffer = NULL;
  1986. ULONG HeaderSize;
  1987. ULONG AppendPointerSize = 0;
  1988. struct WMI_LOGFILE_HEADER {
  1989. WMI_BUFFER_HEADER BufferHeader;
  1990. SYSTEM_TRACE_HEADER SystemHeader;
  1991. TRACE_LOGFILE_HEADER LogFileHeader;
  1992. };
  1993. struct WMI_LOGFILE_HEADER LoggerBuffer;
  1994. BOOLEAN bLogFileAppend =
  1995. (LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_APPEND)
  1996. ? (TRUE) : (FALSE);
  1997. if ((LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_NEWFILE) &&
  1998. (LoggerInfo->LogFileName.Length > 0)) {
  1999. HRESULT hr;
  2000. FileName = (LPWSTR) EtwpAlloc(LoggerInfo->LogFileName.Length + 64);
  2001. if (FileName == NULL) {
  2002. return EtwpSetDosError(ERROR_NOT_ENOUGH_MEMORY);
  2003. }
  2004. //
  2005. // The LogFilePatten has already been validated
  2006. //
  2007. hr = StringCbPrintfW(FileName,
  2008. LoggerInfo->LogFileName.Length + 64,
  2009. LoggerInfo->LogFileName.Buffer,
  2010. 1);
  2011. if (FAILED(hr)) {
  2012. EtwpFree(FileName);
  2013. return HRESULT_CODE(hr);
  2014. }
  2015. FileNameBuffer = FileName;
  2016. }
  2017. if (FileName == NULL)
  2018. FileName = (LPWSTR) LoggerInfo->LogFileName.Buffer;
  2019. //
  2020. // If it is Append Mode, we need to open the file and make sure the
  2021. // pick up the BufferSize
  2022. //
  2023. if ( bLogFileAppend ) {
  2024. FILE_STANDARD_INFORMATION FileStdInfo;
  2025. ULONG ReadSize = sizeof(WMI_BUFFER_HEADER)
  2026. + sizeof(SYSTEM_TRACE_HEADER)
  2027. + sizeof(TRACE_LOGFILE_HEADER);
  2028. ULONG nBytesRead = 0;
  2029. //
  2030. // Update and Append do not mix. To Append LoggerInfo
  2031. // must have LogFileName
  2032. //
  2033. if ( (Update) || (LoggerInfo->LogFileName.Length <= 0) ) {
  2034. if (FileNameBuffer != NULL) {
  2035. EtwpFree(FileNameBuffer);
  2036. }
  2037. return EtwpSetDosError(ERROR_INVALID_PARAMETER);
  2038. }
  2039. LogFile = EtwpCreateFileW(FileName,
  2040. GENERIC_READ | GENERIC_WRITE,
  2041. FILE_SHARE_READ,
  2042. NULL,
  2043. OPEN_EXISTING,
  2044. FILE_ATTRIBUTE_NORMAL,
  2045. NULL);
  2046. if (LogFile == INVALID_HANDLE_VALUE) {
  2047. // cannot OPEN_EXISTING, assume that logfile is not there and
  2048. // create a new one.
  2049. //
  2050. bLogFileAppend = FALSE;
  2051. LoggerInfo->LogFileMode = LoggerInfo->LogFileMode
  2052. & (~ (EVENT_TRACE_FILE_MODE_APPEND));
  2053. }
  2054. else {
  2055. // read TRACE_LOGFILE_HEADER structure and update LoggerInfo
  2056. // members.
  2057. //
  2058. Status = EtwpReadFile(LogFile,
  2059. (LPVOID) & LoggerBuffer,
  2060. ReadSize,
  2061. & nBytesRead,
  2062. NULL);
  2063. if (nBytesRead < ReadSize) {
  2064. NtClose(LogFile);
  2065. if (FileNameBuffer != NULL) {
  2066. EtwpFree(FileNameBuffer);
  2067. }
  2068. return EtwpSetDosError(ERROR_BAD_PATHNAME);
  2069. }
  2070. if ( LoggerBuffer.LogFileHeader.LogFileMode
  2071. & EVENT_TRACE_FILE_MODE_CIRCULAR) {
  2072. NtClose(LogFile);
  2073. if (FileNameBuffer != NULL) {
  2074. EtwpFree(FileNameBuffer);
  2075. }
  2076. return EtwpSetDosError(ERROR_BAD_PATHNAME);
  2077. }
  2078. AppendPointerSize = LoggerBuffer.LogFileHeader.PointerSize;
  2079. LoggerInfo->BufferSize =
  2080. LoggerBuffer.LogFileHeader.BufferSize / 1024;
  2081. //
  2082. // Check to see if the values from the logfile are valid.
  2083. //
  2084. if ( (LoggerInfo->BufferSize == 0) ||
  2085. (LoggerInfo->BufferSize > MAX_ETW_BUFFERSIZE) ) {
  2086. NtClose(LogFile);
  2087. if (FileNameBuffer != NULL) {
  2088. EtwpFree(FileNameBuffer);
  2089. }
  2090. return EtwpSetDosError(ERROR_INVALID_DATA);
  2091. }
  2092. //
  2093. // If it's append, the GuidMap buffers are not accounted for
  2094. // in the BuffersWritten count. The starttrace call will fail
  2095. // on checksum error if it is not adjusted properly. However,
  2096. // this will trash the GuidMap entries in this file.
  2097. //
  2098. Status = NtQueryInformationFile(
  2099. LogFile,
  2100. &IoStatus,
  2101. &FileStdInfo,
  2102. sizeof(FILE_STANDARD_INFORMATION),
  2103. FileStandardInformation
  2104. );
  2105. if (NT_SUCCESS(Status)) {
  2106. ULONG64 FileSize = FileStdInfo.AllocationSize.QuadPart;
  2107. ULONG64 BuffersWritten = 0;
  2108. if (LoggerBuffer.LogFileHeader.BufferSize > 0) {
  2109. BuffersWritten = FileSize /
  2110. (ULONG64)LoggerBuffer.LogFileHeader.BufferSize;
  2111. }
  2112. LoggerInfo->BuffersWritten = (ULONG)BuffersWritten;
  2113. LoggerBuffer.LogFileHeader.BuffersWritten = (ULONG)BuffersWritten;
  2114. }
  2115. else {
  2116. NtClose(LogFile);
  2117. if (FileNameBuffer != NULL) {
  2118. EtwpFree(FileNameBuffer);
  2119. }
  2120. return EtwpNtStatusToDosError(Status);
  2121. }
  2122. LoggerInfo->MaximumFileSize =
  2123. LoggerBuffer.LogFileHeader.MaximumFileSize;
  2124. // Write back logfile append mode so EtwpFinalizeLogFile() correctly
  2125. // update BuffersWritten field
  2126. //
  2127. FileInfo.CurrentByteOffset.QuadPart =
  2128. LOGFILE_FIELD_OFFSET(EndTime);
  2129. Status = NtSetInformationFile(LogFile,
  2130. & IoStatus,
  2131. & FileInfo,
  2132. sizeof(FILE_POSITION_INFORMATION),
  2133. FilePositionInformation);
  2134. if (!NT_SUCCESS(Status)) {
  2135. NtClose(LogFile);
  2136. if (FileNameBuffer != NULL) {
  2137. EtwpFree(FileNameBuffer);
  2138. }
  2139. return EtwpSetDosError(EtwpNtStatusToDosError(Status));
  2140. }
  2141. LoggerBuffer.LogFileHeader.EndTime.QuadPart = 0;
  2142. Status = NtWriteFile(LogFile,
  2143. NULL,
  2144. NULL,
  2145. NULL,
  2146. & IoStatus,
  2147. & LoggerBuffer.LogFileHeader.EndTime,
  2148. sizeof(LARGE_INTEGER),
  2149. NULL,
  2150. NULL);
  2151. if (! NT_SUCCESS(Status)) {
  2152. NtClose(LogFile);
  2153. if (FileNameBuffer != NULL) {
  2154. EtwpFree(FileNameBuffer);
  2155. }
  2156. return EtwpSetDosError(EtwpNtStatusToDosError(Status));
  2157. }
  2158. // build checksum structure
  2159. //
  2160. if (LoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) {
  2161. LoggerInfo->Checksum = NULL;
  2162. }
  2163. else {
  2164. LoggerInfo->Checksum = EtwpAlloc(
  2165. sizeof(WNODE_HEADER) + sizeof(TRACE_LOGFILE_HEADER));
  2166. if (LoggerInfo->Checksum != NULL) {
  2167. PBYTE ptrChecksum = LoggerInfo->Checksum;
  2168. RtlCopyMemory(ptrChecksum,
  2169. & LoggerBuffer.BufferHeader,
  2170. sizeof(WNODE_HEADER));
  2171. ptrChecksum += sizeof(WNODE_HEADER);
  2172. RtlCopyMemory(ptrChecksum,
  2173. & LoggerBuffer.LogFileHeader,
  2174. sizeof(TRACE_LOGFILE_HEADER));
  2175. }
  2176. else {
  2177. NtClose(LogFile);
  2178. if (FileNameBuffer != NULL) {
  2179. EtwpFree(FileNameBuffer);
  2180. }
  2181. return EtwpSetDosError(ERROR_NOT_ENOUGH_MEMORY);
  2182. }
  2183. }
  2184. }
  2185. }
  2186. // get the system parameters first
  2187. LoggerInfo->LogFileHandle = NULL;
  2188. Status = NtQuerySystemInformation(
  2189. SystemBasicInformation,
  2190. &SystemInfo, sizeof (SystemInfo), NULL);
  2191. if (!NT_SUCCESS(Status)) {
  2192. if (LogFile != INVALID_HANDLE_VALUE) {
  2193. // for APPEND case, the file is already opened
  2194. NtClose(LogFile);
  2195. }
  2196. if (FileNameBuffer != NULL) {
  2197. EtwpFree(FileNameBuffer);
  2198. }
  2199. if (LoggerInfo->Checksum != NULL) {
  2200. EtwpFree(LoggerInfo->Checksum);
  2201. }
  2202. LoggerInfo->Checksum = NULL;
  2203. return EtwpSetDosError(EtwpNtStatusToDosError(Status));
  2204. }
  2205. // choose some logical default value for buffer size if user
  2206. // has not provided one
  2207. MemorySize = (ULONG)(SystemInfo.NumberOfPhysicalPages * SystemInfo.PageSize
  2208. / 1024 / 1024);
  2209. if (MemorySize <= 64) {
  2210. BufferSize = SystemInfo.PageSize;
  2211. }
  2212. else if (MemorySize <= 512) {
  2213. BufferSize = SystemInfo.PageSize * 2;
  2214. }
  2215. else {
  2216. BufferSize = 64 * 1024; // allocation size
  2217. }
  2218. if (LoggerInfo->BufferSize > 1024) // limit to 1Mb
  2219. BufferSize = 1024 * 1024;
  2220. else if (LoggerInfo->BufferSize > 0)
  2221. BufferSize = LoggerInfo->BufferSize * 1024;
  2222. TraceKernel = IsEqualGUID(&LoggerInfo->Wnode.Guid, &SystemTraceControlGuid);
  2223. if (!TraceKernel) {
  2224. GUID guid;
  2225. RtlZeroMemory(&guid, sizeof(GUID));
  2226. if (IsEqualGUID(&LoggerInfo->Wnode.Guid, &guid)) {
  2227. // Generate a Guid for this logger stream
  2228. // This will ensure buffer filtering at the WMI service
  2229. // based on this GUID.
  2230. UUID uid;
  2231. EtwpUuidCreate(&uid);
  2232. LoggerInfo->Wnode.Guid = uid;
  2233. }
  2234. }
  2235. if (LoggerInfo->LogFileName.Length <= 0) {
  2236. if (LogFile != INVALID_HANDLE_VALUE) {
  2237. // for APPEND case, the file is already opened
  2238. NtClose(LogFile);
  2239. }
  2240. if (FileNameBuffer != NULL) {
  2241. EtwpFree(FileNameBuffer);
  2242. }
  2243. if (LoggerInfo->Checksum != NULL) {
  2244. EtwpFree(LoggerInfo->Checksum);
  2245. }
  2246. LoggerInfo->Checksum = NULL;
  2247. return ERROR_SUCCESS; //goto SendToKm;
  2248. }
  2249. //
  2250. // We assumed the exposed API has checked for either RealTime or FileName
  2251. // is provided
  2252. //
  2253. // If this is an Update call, then we need to pick up the original
  2254. // buffer size for the LogFileHeader.
  2255. // Otherwise, use the one computed above.
  2256. //
  2257. // For private loggers, a valid logger info is already given. Also,
  2258. // we can't afford nested IOCTL/MBReply for doing QueryLogger.
  2259. //
  2260. if (!Update) {
  2261. LoggerInfo->BufferSize = BufferSize / 1024;
  2262. }
  2263. else if (!(LoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE)) {
  2264. // Update case. This block is not needed for private loggers.
  2265. PWMI_LOGGER_INFORMATION pTempLoggerInfo;
  2266. PWCHAR strLoggerName = NULL;
  2267. PWCHAR strLogFileName = NULL;
  2268. ULONG ErrCode;
  2269. ULONG SizeNeeded = sizeof(WMI_LOGGER_INFORMATION) + MAXSTR * sizeof(WCHAR) * 2;
  2270. ULONG CurrentProcWow = FALSE;
  2271. SizeNeeded = (SizeNeeded +7) & ~7;
  2272. pTempLoggerInfo = EtwpAlloc(SizeNeeded);
  2273. if (pTempLoggerInfo == NULL) {
  2274. if (FileNameBuffer != NULL) {
  2275. EtwpFree(FileNameBuffer);
  2276. }
  2277. return EtwpSetDosError(ERROR_NOT_ENOUGH_MEMORY);
  2278. }
  2279. RtlZeroMemory(pTempLoggerInfo, SizeNeeded);
  2280. pTempLoggerInfo->Wnode.BufferSize = SizeNeeded;
  2281. pTempLoggerInfo->Wnode.Flags |= WNODE_FLAG_TRACED_GUID;
  2282. pTempLoggerInfo->Wnode.HistoricalContext = LoggerInfo->Wnode.HistoricalContext;
  2283. pTempLoggerInfo->Wnode.Guid = LoggerInfo->Wnode.Guid;
  2284. strLoggerName = (PWCHAR) ( ((PUCHAR) pTempLoggerInfo)
  2285. + sizeof(WMI_LOGGER_INFORMATION));
  2286. EtwpInitString(&pTempLoggerInfo->LoggerName,
  2287. strLoggerName,
  2288. MAXSTR * sizeof(WCHAR));
  2289. if (LoggerInfo->LoggerName.Length > 0) {
  2290. RtlCopyUnicodeString( &pTempLoggerInfo->LoggerName,
  2291. &LoggerInfo->LoggerName);
  2292. }
  2293. strLogFileName = (PWCHAR) ( ((PUCHAR) pTempLoggerInfo)
  2294. + sizeof(WMI_LOGGER_INFORMATION)
  2295. + MAXSTR * sizeof(WCHAR) );
  2296. EtwpInitString(&pTempLoggerInfo->LogFileName,
  2297. strLogFileName,
  2298. MAXSTR * sizeof(WCHAR) );
  2299. //
  2300. // Call QueryLogger
  2301. //
  2302. ErrCode = EtwpQueryLogger(pTempLoggerInfo, FALSE);
  2303. if (ErrCode != ERROR_SUCCESS) {
  2304. EtwpFree(pTempLoggerInfo);
  2305. if (FileNameBuffer != NULL) {
  2306. EtwpFree(FileNameBuffer);
  2307. }
  2308. if (LoggerInfo->Checksum != NULL) {
  2309. EtwpFree(LoggerInfo->Checksum);
  2310. }
  2311. LoggerInfo->Checksum = NULL;
  2312. return EtwpSetDosError(ErrCode);
  2313. }
  2314. BufferSize = pTempLoggerInfo->BufferSize * 1024;
  2315. if (!TraceKernel && (sizeof(PVOID) != 8)) {
  2316. // For kernel trace, the pointer size is always 64 on ia64,
  2317. // whether or not under Wow64.
  2318. // Get Wow64 information, set the flag, and adjust the pointer size.
  2319. ULONG_PTR ulp;
  2320. Status = NtQueryInformationProcess(
  2321. NtCurrentProcess(),
  2322. ProcessWow64Information,
  2323. &ulp,
  2324. sizeof(ULONG_PTR),
  2325. NULL);
  2326. if (NT_SUCCESS(Status) && (ulp != 0)) {
  2327. CurrentProcWow = TRUE;
  2328. }
  2329. }
  2330. if ( (pTempLoggerInfo->Wow && !TraceKernel && 8 == sizeof(PVOID)) ||
  2331. (CurrentProcWow && !(pTempLoggerInfo->Wow)) ) {
  2332. // We're trying to do 64 bit mode update on a non-kernel logger
  2333. // that started in 32 bit, or vice versa. We don't allow this.
  2334. EtwpFree(pTempLoggerInfo);
  2335. if (FileNameBuffer != NULL) {
  2336. EtwpFree(FileNameBuffer);
  2337. }
  2338. if (LoggerInfo->Checksum != NULL) {
  2339. EtwpFree(LoggerInfo->Checksum);
  2340. }
  2341. LoggerInfo->Checksum = NULL;
  2342. return EtwpSetDosError(ERROR_NOT_SUPPORTED);
  2343. }
  2344. EtwpFree(pTempLoggerInfo);
  2345. }
  2346. //
  2347. // Now open the file for writing synchronously for the logger
  2348. // others may want to read it as well.
  2349. // For logfile append mode, logfile has been opened previously
  2350. //
  2351. if (!bLogFileAppend) {
  2352. LogFile = EtwpCreateFileW(
  2353. FileName,
  2354. GENERIC_WRITE,
  2355. FILE_SHARE_READ,
  2356. NULL,
  2357. CREATE_ALWAYS,
  2358. FILE_ATTRIBUTE_NORMAL,
  2359. NULL);
  2360. if (LogFile == INVALID_HANDLE_VALUE) {
  2361. if (FileNameBuffer != NULL) {
  2362. EtwpFree(FileNameBuffer);
  2363. }
  2364. return EtwpGetLastError();
  2365. }
  2366. }
  2367. LoggerInfo->LogFileHandle = LogFile;
  2368. //
  2369. // All returns for error cases should have NtClose(LogFile).
  2370. //
  2371. if (TraceKernel && (sizeof(PVOID) != 8)) {
  2372. // For kernel trace, the pointer size is always 64 on ia64,
  2373. // whether or not under Wow64.
  2374. // Get Wow64 information, set the flag, and adjust the pointer size.
  2375. ULONG_PTR ulp;
  2376. Status = NtQueryInformationProcess(
  2377. NtCurrentProcess(),
  2378. ProcessWow64Information,
  2379. &ulp,
  2380. sizeof(ULONG_PTR),
  2381. NULL);
  2382. if (NT_SUCCESS(Status) && (ulp != 0)) {
  2383. KernelWow64 = TRUE;
  2384. }
  2385. }
  2386. //
  2387. // Before Allocating the Buffer for Logfile Header make
  2388. // sure the buffer size is atleast as large as the LogFileHeader
  2389. //
  2390. if (!KernelWow64) {
  2391. HeaderSize = sizeof(LoggerBuffer)
  2392. + LoggerInfo->LoggerName.Length + sizeof(WCHAR)
  2393. + LoggerInfo->LogFileName.Length + sizeof(WCHAR);
  2394. }
  2395. else {
  2396. HeaderSize = sizeof(LoggerBuffer)
  2397. + LoggerInfo->LoggerName.Length + sizeof(WCHAR)
  2398. + LoggerInfo->LogFileName.Length + sizeof(WCHAR)
  2399. + 8;
  2400. }
  2401. if (HeaderSize > BufferSize) {
  2402. //
  2403. // Round it to the nearest power of 2 and check for max size 1 MB
  2404. //
  2405. double dTemp = log (HeaderSize / 1024.0) / log (2.0);
  2406. ULONG lTemp = (ULONG) (dTemp + 0.99);
  2407. HeaderSize = (1 << lTemp);
  2408. if (HeaderSize > 1024) {
  2409. NtClose(LogFile);
  2410. LoggerInfo->LogFileHandle = NULL;
  2411. if (FileNameBuffer != NULL) {
  2412. EtwpFree(FileNameBuffer);
  2413. }
  2414. if (LoggerInfo->Checksum != NULL) {
  2415. EtwpFree(LoggerInfo->Checksum);
  2416. }
  2417. LoggerInfo->Checksum = NULL;
  2418. return EtwpSetDosError(ERROR_NOT_ENOUGH_MEMORY);
  2419. }
  2420. LoggerInfo->BufferSize = HeaderSize;
  2421. BufferSize = HeaderSize * 1024;
  2422. }
  2423. //
  2424. // allocate a buffer to write logger header and process/thread
  2425. // rundown information
  2426. //
  2427. Logger.LogFileHandle = LogFile;
  2428. Logger.BufferSize = BufferSize;
  2429. Logger.TimerResolution = SystemInfo.TimerResolution;
  2430. Logger.BufferSpace = EtwpAlloc(BufferSize);
  2431. if (Logger.BufferSpace == NULL) {
  2432. NtClose(LogFile);
  2433. LoggerInfo->LogFileHandle = NULL;
  2434. if (FileNameBuffer != NULL) {
  2435. EtwpFree(FileNameBuffer);
  2436. }
  2437. if (LoggerInfo->Checksum != NULL) {
  2438. EtwpFree(LoggerInfo->Checksum);
  2439. }
  2440. LoggerInfo->Checksum = NULL;
  2441. return EtwpSetDosError(ERROR_NOT_ENOUGH_MEMORY);
  2442. }
  2443. //
  2444. // All returns for error cases must have EtwpFree(Logger.BufferSpace) also.
  2445. //
  2446. Logger.UsePerfClock = LoggerInfo->Wnode.ClientContext;
  2447. // initialize buffer first
  2448. RtlZeroMemory(Logger.BufferSpace, BufferSize);
  2449. Buffer = (PWMI_BUFFER_HEADER) Logger.BufferSpace;
  2450. Buffer->Offset = sizeof(WMI_BUFFER_HEADER);
  2451. if (TraceKernel) {
  2452. Buffer->Wnode.Guid = SystemTraceControlGuid;
  2453. }
  2454. else {
  2455. Buffer->Wnode.Guid = LoggerInfo->Wnode.Guid;
  2456. }
  2457. Buffer->Wnode.BufferSize = BufferSize;
  2458. Buffer->ClientContext.Alignment = (UCHAR)WmiTraceAlignment;
  2459. Buffer->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
  2460. Buffer->BufferType = WMI_BUFFER_TYPE_RUNDOWN;
  2461. Buffer->BufferFlag = WMI_BUFFER_FLAG_FLUSH_MARKER;
  2462. if (bLogFileAppend) {
  2463. ULONG CurrentPointerSize = sizeof(PVOID);
  2464. if (KernelWow64) {
  2465. CurrentPointerSize = sizeof(ULONG64);
  2466. }
  2467. if (AppendPointerSize != CurrentPointerSize) {
  2468. NtClose(LogFile);
  2469. LoggerInfo->LogFileHandle = NULL;
  2470. if (FileNameBuffer != NULL) {
  2471. EtwpFree(FileNameBuffer);
  2472. }
  2473. if (LoggerInfo->Checksum != NULL) {
  2474. EtwpFree(LoggerInfo->Checksum);
  2475. }
  2476. LoggerInfo->Checksum = NULL;
  2477. return EtwpSetDosError(ERROR_INVALID_PARAMETER);
  2478. }
  2479. Logger.BuffersWritten = LoggerBuffer.LogFileHeader.BuffersWritten;
  2480. EtwpSetFilePointer(LogFile, 0, NULL, FILE_END);
  2481. }
  2482. else {
  2483. PTRACE_LOGFILE_HEADER LogfileHeader;
  2484. LARGE_INTEGER CurrentTime;
  2485. LARGE_INTEGER Frequency;
  2486. ULONG CpuNum = 0, CpuSpeed;
  2487. PPEB Peb;
  2488. Status = NtQueryPerformanceCounter(&CurrentTime, &Frequency);
  2489. Logger.BuffersWritten = 0;
  2490. if (!KernelWow64) {
  2491. HeaderSize = sizeof(TRACE_LOGFILE_HEADER)
  2492. + LoggerInfo->LoggerName.Length + sizeof(WCHAR)
  2493. + LoggerInfo->LogFileName.Length + sizeof(WCHAR);
  2494. }
  2495. else {
  2496. HeaderSize = sizeof(TRACE_LOGFILE_HEADER)
  2497. + LoggerInfo->LoggerName.Length + sizeof(WCHAR)
  2498. + LoggerInfo->LogFileName.Length + sizeof(WCHAR)
  2499. + 8;
  2500. }
  2501. LogfileHeader = (PTRACE_LOGFILE_HEADER)
  2502. EtwpGetTraceBuffer(
  2503. &Logger,
  2504. NULL,
  2505. EVENT_TRACE_GROUP_HEADER + EVENT_TRACE_TYPE_INFO,
  2506. HeaderSize
  2507. );
  2508. if (LogfileHeader == NULL) {
  2509. NtClose(LogFile);
  2510. LoggerInfo->LogFileHandle = NULL;
  2511. EtwpFree(Logger.BufferSpace);
  2512. if (FileNameBuffer != NULL) {
  2513. EtwpFree(FileNameBuffer);
  2514. }
  2515. if (LoggerInfo->Checksum != NULL) {
  2516. EtwpFree(LoggerInfo->Checksum);
  2517. }
  2518. LoggerInfo->Checksum = NULL;
  2519. return EtwpSetDosError(ERROR_NOT_ENOUGH_MEMORY);
  2520. }
  2521. LogfileHeader->PerfFreq = Frequency;
  2522. LogfileHeader->ReservedFlags = Logger.UsePerfClock;
  2523. if (NT_SUCCESS(EtwpGetCpuSpeed(&CpuNum, &CpuSpeed))) {
  2524. LogfileHeader->CpuSpeedInMHz = CpuSpeed;
  2525. }
  2526. //
  2527. // Start and End Times are wall clock time
  2528. //
  2529. if (RefClock != NULL) {
  2530. PSYSTEM_TRACE_HEADER Header;
  2531. LogfileHeader->StartTime = RefClock->StartTime;
  2532. Header = (PSYSTEM_TRACE_HEADER) ( (char *) LogfileHeader -
  2533. sizeof(SYSTEM_TRACE_HEADER) );
  2534. Header->SystemTime = RefClock->StartPerfClock;
  2535. }
  2536. else {
  2537. LogfileHeader->StartTime.QuadPart = EtwpGetSystemTime();
  2538. }
  2539. Peb = NtCurrentPeb();
  2540. LogfileHeader->BufferSize = BufferSize;
  2541. LogfileHeader->VersionDetail.MajorVersion =
  2542. (UCHAR)Peb->OSMajorVersion;
  2543. LogfileHeader->VersionDetail.MinorVersion =
  2544. (UCHAR)Peb->OSMinorVersion;
  2545. LogfileHeader->VersionDetail.SubVersion = TRACE_VERSION_MAJOR;
  2546. LogfileHeader->VersionDetail.SubMinorVersion = TRACE_VERSION_MINOR;
  2547. LogfileHeader->ProviderVersion = Peb->OSBuildNumber;
  2548. LogfileHeader->StartBuffers = 1;
  2549. LogfileHeader->LogFileMode
  2550. = LoggerInfo->LogFileMode & (~(EVENT_TRACE_REAL_TIME_MODE));
  2551. LogfileHeader->NumberOfProcessors = SystemInfo.NumberOfProcessors;
  2552. if (LoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE)
  2553. {
  2554. LoggerInfo->NumberOfProcessors = SystemInfo.NumberOfProcessors;
  2555. }
  2556. LogfileHeader->MaximumFileSize = LoggerInfo->MaximumFileSize;
  2557. LogfileHeader->TimerResolution = SystemInfo.TimerResolution;
  2558. LogfileHeader->LoggerName = (PWCHAR) ( (PUCHAR) LogfileHeader
  2559. + sizeof(TRACE_LOGFILE_HEADER) );
  2560. LogfileHeader->LogFileName = (PWCHAR) ((PUCHAR)LogfileHeader->LoggerName
  2561. + LoggerInfo->LoggerName.Length
  2562. + sizeof (WCHAR));
  2563. RtlCopyMemory(LogfileHeader->LoggerName,
  2564. LoggerInfo->LoggerName.Buffer,
  2565. LoggerInfo->LoggerName.Length + sizeof(WCHAR));
  2566. RtlCopyMemory(LogfileHeader->LogFileName,
  2567. LoggerInfo->LogFileName.Buffer,
  2568. LoggerInfo->LogFileName.Length + sizeof(WCHAR));
  2569. EtwpGetTimeZoneInformation(&LogfileHeader->TimeZone);
  2570. LogfileHeader->PointerSize = sizeof(PVOID);
  2571. if (KernelWow64) {
  2572. LogfileHeader->PointerSize = sizeof(ULONG64);
  2573. }
  2574. if (LoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) {
  2575. LoggerInfo->Checksum = NULL;
  2576. }
  2577. else {
  2578. LoggerInfo->Checksum = EtwpAlloc(
  2579. sizeof(WNODE_HEADER)
  2580. + sizeof(TRACE_LOGFILE_HEADER));
  2581. if (LoggerInfo->Checksum != NULL) {
  2582. PBYTE ptrChecksum = LoggerInfo->Checksum;
  2583. RtlCopyMemory(ptrChecksum, Buffer, sizeof(WNODE_HEADER));
  2584. ptrChecksum += sizeof(WNODE_HEADER);
  2585. RtlCopyMemory(
  2586. ptrChecksum, LogfileHeader, sizeof(TRACE_LOGFILE_HEADER));
  2587. }
  2588. else {
  2589. NtClose(LogFile);
  2590. LoggerInfo->LogFileHandle = NULL;
  2591. EtwpFree(Logger.BufferSpace);
  2592. if (FileNameBuffer != NULL) {
  2593. EtwpFree(FileNameBuffer);
  2594. }
  2595. if (LoggerInfo->Checksum != NULL) {
  2596. EtwpFree(LoggerInfo->Checksum);
  2597. }
  2598. LoggerInfo->Checksum = NULL;
  2599. return EtwpSetDosError(ERROR_NOT_ENOUGH_MEMORY);
  2600. }
  2601. }
  2602. if (KernelWow64) {
  2603. // ****************** IMPORTANT!!! *********************************
  2604. // We need to fix the kernel logfile header here so that the
  2605. // header looks like 64 bit structure under Wow64. After this point,
  2606. // BuffersWritten and StartBuffers are updated in this function
  2607. // after this point, but they are below the troublesome pointers,
  2608. // so it's OK.
  2609. ULONG FixedHeaderStatus = EtwpFixLogFileHeaderForWow64(
  2610. LoggerInfo,
  2611. LogfileHeader
  2612. );
  2613. if (FixedHeaderStatus != ERROR_SUCCESS) {
  2614. NtClose(LogFile);
  2615. LoggerInfo->LogFileHandle = NULL;
  2616. EtwpFree(Logger.BufferSpace);
  2617. if (FileNameBuffer != NULL) {
  2618. EtwpFree(FileNameBuffer);
  2619. }
  2620. if (LoggerInfo->Checksum != NULL) {
  2621. EtwpFree(LoggerInfo->Checksum);
  2622. }
  2623. LoggerInfo->Checksum = NULL;
  2624. return EtwpSetDosError(FixedHeaderStatus);
  2625. }
  2626. }
  2627. }
  2628. //
  2629. // Dump the hardware config to File at the Start if it is a kernel logger
  2630. //
  2631. if (!Update) {
  2632. if (TraceKernel) {
  2633. ULONG EnableFlags = LoggerInfo->EnableFlags;
  2634. PPERFINFO_GROUPMASK PGroupMask;
  2635. HeaderSize = sizeof (PERFINFO_GROUPMASK);
  2636. PGroupMask = (PPERFINFO_GROUPMASK)
  2637. EtwpGetTraceBuffer( &Logger,
  2638. NULL,
  2639. EVENT_TRACE_GROUP_HEADER + EVENT_TRACE_TYPE_EXTENSION,
  2640. HeaderSize );
  2641. if (PGroupMask == NULL) {
  2642. NtClose(LogFile);
  2643. LoggerInfo->LogFileHandle = NULL;
  2644. EtwpFree(Logger.BufferSpace);
  2645. if (FileNameBuffer != NULL) {
  2646. EtwpFree(FileNameBuffer);
  2647. }
  2648. if (LoggerInfo->Checksum != NULL) {
  2649. EtwpFree(LoggerInfo->Checksum);
  2650. }
  2651. LoggerInfo->Checksum = NULL;
  2652. return EtwpSetDosError(ERROR_NOT_ENOUGH_MEMORY);
  2653. }
  2654. RtlZeroMemory( PGroupMask, HeaderSize);
  2655. if (EnableFlags & EVENT_TRACE_FLAG_EXTENSION) {
  2656. PTRACE_ENABLE_FLAG_EXTENSION tFlagExt;
  2657. tFlagExt = (PTRACE_ENABLE_FLAG_EXTENSION)
  2658. &LoggerInfo->EnableFlags;
  2659. EnableFlags = *(PULONG)((PCHAR)LoggerInfo + tFlagExt->Offset);
  2660. if (tFlagExt->Length) {
  2661. RtlCopyMemory( PGroupMask,
  2662. (PCHAR)LoggerInfo + tFlagExt->Offset,
  2663. tFlagExt->Length * sizeof(ULONG));
  2664. }
  2665. } else {
  2666. PGroupMask->Masks[0] = EnableFlags;
  2667. }
  2668. EtwpDumpHardwareConfig(&Logger);
  2669. EtwpProcessRunDown( &Logger, TRUE, EnableFlags );
  2670. }
  2671. else {
  2672. if(IsEqualGUID(&NtdllTraceGuid, &LoggerInfo->Wnode.Guid) &&
  2673. IsHeapLogging(NULL)){
  2674. //Currently the return status of DumpHeapSnapShot is ignored.
  2675. DumpHeapSnapShot(&Logger);
  2676. }
  2677. }
  2678. }
  2679. Buffer = (PWMI_BUFFER_HEADER) Logger.BufferSpace;
  2680. // flush the last buffer
  2681. if ( (Buffer->Offset < Logger.BufferSize) &&
  2682. (Buffer->Offset > sizeof(WMI_BUFFER_HEADER)) )
  2683. {
  2684. RtlFillMemory(
  2685. (char *) Buffer + Buffer->Offset,
  2686. Logger.BufferSize - Buffer->Offset,
  2687. 0xFF);
  2688. Status = NtWriteFile(
  2689. LogFile,
  2690. NULL,
  2691. NULL,
  2692. NULL,
  2693. &IoStatus,
  2694. Logger.BufferSpace,
  2695. BufferSize,
  2696. NULL,
  2697. NULL);
  2698. Logger.BuffersWritten++;
  2699. }
  2700. if ((LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_CIRCULAR) ) {
  2701. // We need to write the number of StartBuffers in the
  2702. // Circular Logfile header to process it properly.
  2703. FileInfo.CurrentByteOffset.QuadPart =
  2704. LOGFILE_FIELD_OFFSET(StartBuffers);
  2705. Status = NtSetInformationFile(
  2706. LogFile,
  2707. &IoStatus,
  2708. &FileInfo,
  2709. sizeof(FILE_POSITION_INFORMATION),
  2710. FilePositionInformation
  2711. );
  2712. if (!NT_SUCCESS(Status)) {
  2713. NtClose(LogFile);
  2714. LoggerInfo->LogFileHandle = NULL;
  2715. EtwpFree(Logger.BufferSpace);
  2716. if (FileNameBuffer != NULL) {
  2717. EtwpFree(FileNameBuffer);
  2718. }
  2719. if (LoggerInfo->Checksum != NULL) {
  2720. EtwpFree(LoggerInfo->Checksum);
  2721. }
  2722. LoggerInfo->Checksum = NULL;
  2723. return EtwpSetDosError(EtwpNtStatusToDosError(Status));
  2724. }
  2725. Status = NtWriteFile(
  2726. LogFile,
  2727. NULL,
  2728. NULL,
  2729. NULL,
  2730. &IoStatus,
  2731. &Logger.BuffersWritten,
  2732. sizeof(ULONG),
  2733. NULL,
  2734. NULL
  2735. );
  2736. if (NT_SUCCESS(Status)) {
  2737. PTRACE_LOGFILE_HEADER pLogFileHeader;
  2738. NtFlushBuffersFile(Logger.LogFileHandle, &IoStatus);
  2739. //
  2740. // update StartBuffers in Checksum
  2741. //
  2742. if ( !(LoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE)) {
  2743. // Checksum should have been allocated and copied
  2744. // if not a private logger
  2745. if (LoggerInfo->Checksum == NULL) {
  2746. NtClose(LogFile);
  2747. LoggerInfo->LogFileHandle = NULL;
  2748. EtwpFree(Logger.BufferSpace);
  2749. if (FileNameBuffer != NULL) {
  2750. EtwpFree(FileNameBuffer);
  2751. }
  2752. if (LoggerInfo->Checksum != NULL) {
  2753. EtwpFree(LoggerInfo->Checksum);
  2754. }
  2755. LoggerInfo->Checksum = NULL;
  2756. return EtwpSetDosError(ERROR_INVALID_DATA);
  2757. }
  2758. pLogFileHeader = (PTRACE_LOGFILE_HEADER)
  2759. (((PUCHAR) LoggerInfo->Checksum) + sizeof(WNODE_HEADER));
  2760. pLogFileHeader->StartBuffers = Logger.BuffersWritten;
  2761. }
  2762. }
  2763. }
  2764. //
  2765. // As a last thing update the Number of BuffersWritten so far
  2766. // in the header and also update the checksum. This is to prevent
  2767. // Logger failing Update calls under high load.
  2768. //
  2769. FileInfo.CurrentByteOffset.QuadPart =
  2770. LOGFILE_FIELD_OFFSET(BuffersWritten);
  2771. Status = NtSetInformationFile(
  2772. LogFile,
  2773. &IoStatus,
  2774. &FileInfo,
  2775. sizeof(FILE_POSITION_INFORMATION),
  2776. FilePositionInformation
  2777. );
  2778. if (!NT_SUCCESS(Status)) {
  2779. NtClose(LogFile);
  2780. LoggerInfo->LogFileHandle = NULL;
  2781. EtwpFree(Logger.BufferSpace);
  2782. if (FileNameBuffer != NULL) {
  2783. EtwpFree(FileNameBuffer);
  2784. }
  2785. if (LoggerInfo->Checksum != NULL) {
  2786. EtwpFree(LoggerInfo->Checksum);
  2787. }
  2788. LoggerInfo->Checksum = NULL;
  2789. return EtwpSetDosError(EtwpNtStatusToDosError(Status));
  2790. }
  2791. Status = NtWriteFile(
  2792. LogFile,
  2793. NULL,
  2794. NULL,
  2795. NULL,
  2796. &IoStatus,
  2797. &Logger.BuffersWritten,
  2798. sizeof(ULONG),
  2799. NULL,
  2800. NULL
  2801. );
  2802. if (NT_SUCCESS(Status)) {
  2803. PTRACE_LOGFILE_HEADER pLogFileHeader;
  2804. NtFlushBuffersFile(Logger.LogFileHandle, &IoStatus);
  2805. // update StartBuffers in Checksum
  2806. //
  2807. if ( !(LoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE)) {
  2808. // Checksum should have been allocated and copied
  2809. // if not a private logger
  2810. if (LoggerInfo->Checksum == NULL) {
  2811. NtClose(LogFile);
  2812. LoggerInfo->LogFileHandle = NULL;
  2813. EtwpFree(Logger.BufferSpace);
  2814. if (FileNameBuffer != NULL) {
  2815. EtwpFree(FileNameBuffer);
  2816. }
  2817. if (LoggerInfo->Checksum != NULL) {
  2818. EtwpFree(LoggerInfo->Checksum);
  2819. }
  2820. LoggerInfo->Checksum = NULL;
  2821. return EtwpSetDosError(ERROR_INVALID_DATA);
  2822. }
  2823. pLogFileHeader = (PTRACE_LOGFILE_HEADER)
  2824. (((PUCHAR) LoggerInfo->Checksum) + sizeof(WNODE_HEADER));
  2825. pLogFileHeader->BuffersWritten = Logger.BuffersWritten;
  2826. }
  2827. }
  2828. // Extend the file size if in PREALLOCATE mode
  2829. if (LoggerInfo->MaximumFileSize &&
  2830. (LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_PREALLOCATE)) {
  2831. IO_STATUS_BLOCK IoStatusBlock;
  2832. FILE_END_OF_FILE_INFORMATION EOFInfo;
  2833. if (!(LoggerInfo->LogFileMode & EVENT_TRACE_USE_KBYTES_FOR_SIZE)) { // normal case
  2834. EOFInfo.EndOfFile.QuadPart = ((ULONGLONG)LoggerInfo->MaximumFileSize) * (1024 * 1024);
  2835. Status = NtSetInformationFile(LogFile,
  2836. &IoStatusBlock,
  2837. &EOFInfo,
  2838. sizeof(FILE_END_OF_FILE_INFORMATION),
  2839. FileEndOfFileInformation);
  2840. if (!NT_SUCCESS(Status)) {
  2841. NtClose(LogFile);
  2842. LoggerInfo->LogFileHandle = NULL;
  2843. EtwpFree(Logger.BufferSpace);
  2844. if (FileNameBuffer != NULL) {
  2845. EtwpFree(FileNameBuffer);
  2846. }
  2847. if (LoggerInfo->Checksum != NULL) {
  2848. EtwpFree(LoggerInfo->Checksum);
  2849. }
  2850. LoggerInfo->Checksum = NULL;
  2851. return EtwpSetDosError(EtwpNtStatusToDosError(Status));
  2852. }
  2853. }
  2854. else { // Using KBytes as file size unit
  2855. EOFInfo.EndOfFile.QuadPart = ((ULONGLONG)LoggerInfo->MaximumFileSize) * 1024;
  2856. Status = NtSetInformationFile(LogFile,
  2857. &IoStatusBlock,
  2858. &EOFInfo,
  2859. sizeof(FILE_END_OF_FILE_INFORMATION),
  2860. FileEndOfFileInformation);
  2861. if (!NT_SUCCESS(Status)) {
  2862. NtClose(LogFile);
  2863. LoggerInfo->LogFileHandle = NULL;
  2864. EtwpFree(Logger.BufferSpace);
  2865. if (FileNameBuffer != NULL) {
  2866. EtwpFree(FileNameBuffer);
  2867. }
  2868. if (LoggerInfo->Checksum != NULL) {
  2869. EtwpFree(LoggerInfo->Checksum);
  2870. }
  2871. LoggerInfo->Checksum = NULL;
  2872. return EtwpSetDosError(EtwpNtStatusToDosError(Status));
  2873. }
  2874. }
  2875. }
  2876. NtClose(LogFile);
  2877. LogFile = EtwpCreateFileW(
  2878. FileName,
  2879. GENERIC_WRITE,
  2880. FILE_SHARE_READ,
  2881. NULL,
  2882. OPEN_EXISTING,
  2883. FILE_FLAG_NO_BUFFERING,
  2884. NULL
  2885. );
  2886. if (FileNameBuffer != NULL) {
  2887. EtwpFree(FileNameBuffer);
  2888. }
  2889. EtwpFree(Logger.BufferSpace);
  2890. if (LogFile == INVALID_HANDLE_VALUE) {
  2891. if (LoggerInfo->Checksum != NULL) {
  2892. EtwpFree(LoggerInfo->Checksum);
  2893. }
  2894. LoggerInfo->Checksum = NULL;
  2895. return EtwpGetLastError();
  2896. }
  2897. LoggerInfo->LogFileHandle = LogFile;
  2898. LoggerInfo->BuffersWritten = Logger.BuffersWritten;
  2899. return ERROR_SUCCESS;
  2900. }
  2901. ULONG
  2902. WmiUnregisterGuids(
  2903. IN WMIHANDLE WMIHandle,
  2904. IN LPGUID Guid,
  2905. OUT ULONG64 *LoggerContext
  2906. )
  2907. /*++
  2908. Routine Description:
  2909. This routine informs WMI that a data provider is no longer available
  2910. to receive requests for the guids previously registered. WMI will
  2911. unregister any guids registered with this handle.
  2912. Arguments:
  2913. WMIHandle - Handle returned from WMIRegisterGuids that represents
  2914. the guids whose data is not longer available.
  2915. Guid - Pointer to the control Guid which is unregistering
  2916. LoggerContext - Returned value of the LoggerContext
  2917. Return Value:
  2918. Returns status code
  2919. --*/
  2920. {
  2921. ULONG Status;
  2922. ULONG ReturnSize;
  2923. WMIUNREGGUIDS UnregGuids;
  2924. UnregGuids.RequestHandle.Handle64 = (ULONG64)WMIHandle;
  2925. UnregGuids.Guid = *Guid;
  2926. Status = EtwpSendWmiKMRequest(NULL,
  2927. IOCTL_WMI_UNREGISTER_GUIDS,
  2928. &UnregGuids,
  2929. sizeof(WMIUNREGGUIDS),
  2930. &UnregGuids,
  2931. sizeof(WMIUNREGGUIDS),
  2932. &ReturnSize,
  2933. NULL);
  2934. //
  2935. // Once the Guid has been unregistered from the kernel we will not get
  2936. // any new notifications. We still need to wait for any notifications
  2937. // currently in progress. The following call will check for it and
  2938. // block until it is okay to delete the data structures.
  2939. //
  2940. if (Status == ERROR_SUCCESS)
  2941. {
  2942. Status = EtwpRemoveFromGNList(Guid,
  2943. (PVOID) WMIHandle);
  2944. }
  2945. EtwpSetDosError(Status);
  2946. return(Status);
  2947. }
  2948. ULONG
  2949. EtwpFlushLogger(
  2950. IN OUT PWMI_LOGGER_INFORMATION LoggerInfo
  2951. )
  2952. /*++
  2953. Routine Description:
  2954. This is the actual routine to communicate with the kernel to Flush
  2955. the logger. All the required parameters must be in LoggerInfo.
  2956. This is an internal routine and it assumes that the LoggerInfo
  2957. structure has been set up correctly and does not perform any
  2958. additional checks on the structure.
  2959. Arguments:
  2960. LoggerInfo The actual parameters to be passed to and return from
  2961. kernel.
  2962. Return Value:
  2963. The status of performing the action requested.
  2964. --*/
  2965. {
  2966. ULONG Status;
  2967. ULONG BufferSize;
  2968. PTRACE_ENABLE_CONTEXT pContext;
  2969. if (LoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) {
  2970. Status = EtwpSendUmLogRequest(
  2971. WmiFlushLoggerCode,
  2972. LoggerInfo
  2973. );
  2974. }
  2975. else {
  2976. Status = EtwpSendWmiKMRequest(
  2977. NULL,
  2978. IOCTL_WMI_FLUSH_LOGGER,
  2979. LoggerInfo,
  2980. LoggerInfo->Wnode.BufferSize,
  2981. LoggerInfo,
  2982. LoggerInfo->Wnode.BufferSize,
  2983. &BufferSize,
  2984. NULL
  2985. );
  2986. }
  2987. return EtwpSetDosError(Status);
  2988. }
  2989. NTSTATUS
  2990. EtwpGetCpuSpeed(
  2991. OUT DWORD* CpuNum,
  2992. OUT DWORD* CpuSpeed
  2993. )
  2994. {
  2995. PWCHAR Buffer = NULL;
  2996. NTSTATUS Status;
  2997. ULONG DataLength;
  2998. DWORD Size = MAXSTR;
  2999. HANDLE Handle = INVALID_HANDLE_VALUE;
  3000. HRESULT hr;
  3001. *CpuSpeed = 0;
  3002. Buffer = RtlAllocateHeap (RtlProcessHeap(),0,DEFAULT_ALLOC_SIZE);
  3003. if (Buffer == NULL) {
  3004. return STATUS_NO_MEMORY;
  3005. }
  3006. hr = StringCbPrintfW(Buffer,
  3007. DEFAULT_ALLOC_SIZE,
  3008. L"%ws\\%u", CPU_ROOT, *CpuNum
  3009. );
  3010. if (FAILED(hr) ) {
  3011. RtlFreeHeap (RtlProcessHeap(),0,Buffer);
  3012. return STATUS_NO_MEMORY;
  3013. }
  3014. Status = EtwpRegOpenKey(Buffer, &Handle);
  3015. if (NT_SUCCESS(Status)) {
  3016. StringCbCopyW(Buffer, DEFAULT_ALLOC_SIZE, MHZ_VALUE_NAME);
  3017. Size = sizeof(DWORD);
  3018. Status = EtwpRegQueryValueKey(Handle,
  3019. (LPWSTR) Buffer,
  3020. Size,
  3021. CpuSpeed,
  3022. &DataLength
  3023. );
  3024. NtClose(Handle);
  3025. }
  3026. RtlFreeHeap (RtlProcessHeap(),0,Buffer);
  3027. return Status;
  3028. }
  3029. #endif