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

2922 lines
95 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. NTSTATUS
  26. WmipProcessRunDown(
  27. IN PWMI_LOGGER_CONTEXT Logger,
  28. IN ULONG StartFlag,
  29. IN ULONG fEnableFlags
  30. );
  31. NTSTATUS
  32. WmipThreadRunDown(
  33. IN PWMI_LOGGER_CONTEXT Logger,
  34. IN PSYSTEM_PROCESS_INFORMATION pProcessInfo,
  35. IN ULONG StartFlag,
  36. IN BOOLEAN bExtended
  37. );
  38. ULONG WmiTraceAlignment = DEFAULT_TRACE_ALIGNMENT;
  39. ULONG
  40. WmipStartLogger(
  41. IN OUT PWMI_LOGGER_INFORMATION LoggerInfo
  42. )
  43. /*++
  44. Routine Description:
  45. This is the actual routine to communicate with the kernel to start
  46. the logger. All the required parameters must be in LoggerInfo.
  47. Arguments:
  48. LoggerInfo The actual parameters to be passed to and return from
  49. kernel.
  50. Return Value:
  51. The status of performing the action requested.
  52. --*/
  53. {
  54. ULONG Status;
  55. ULONG BufferSize;
  56. ACCESS_MASK DesiredAccess = 0;
  57. LPGUID Guid;
  58. PVOID SavedChecksum;
  59. ULONG SavedLogFileMode;
  60. BOOLEAN IsKernelTrace = FALSE;
  61. BOOLEAN bLogFile = FALSE;
  62. BOOLEAN bRealTime = FALSE;
  63. WMI_REF_CLOCK RefClock;
  64. LARGE_INTEGER RefClockSys, RefClockPerf, RefClockCycle;
  65. LARGE_INTEGER Frequency;
  66. Guid = &LoggerInfo->Wnode.Guid;
  67. if( IsEqualGUID(&HeapGuid,Guid)
  68. || IsEqualGUID(&CritSecGuid,Guid)
  69. ){
  70. WMINTDLLLOGGERINFO NtdllLoggerInfo;
  71. NtdllLoggerInfo.LoggerInfo = LoggerInfo;
  72. RtlCopyMemory(&LoggerInfo->Wnode.Guid, &NtdllTraceGuid, sizeof(GUID));
  73. NtdllLoggerInfo.IsGet = FALSE;
  74. Status = WmipSendWmiKMRequest(
  75. NULL,
  76. IOCTL_WMI_NTDLL_LOGGERINFO,
  77. &NtdllLoggerInfo,
  78. sizeof(WMINTDLLLOGGERINFO),
  79. &NtdllLoggerInfo,
  80. sizeof(WMINTDLLLOGGERINFO),
  81. &BufferSize,
  82. NULL
  83. );
  84. return WmipSetDosError(Status);
  85. }
  86. if (IsEqualGUID(Guid, &SystemTraceControlGuid) ||
  87. IsEqualGUID(Guid, &WmiEventLoggerGuid)) {
  88. IsKernelTrace = TRUE;
  89. DesiredAccess |= TRACELOG_ACCESS_KERNEL_LOGGER;
  90. }
  91. if ((LoggerInfo->LogFileName.Length > 0) &&
  92. (LoggerInfo->LogFileName.Buffer != NULL)) {
  93. DesiredAccess |= TRACELOG_CREATE_ONDISK;
  94. bLogFile = TRUE;
  95. }
  96. SavedLogFileMode = LoggerInfo->LogFileMode;
  97. if (SavedLogFileMode & EVENT_TRACE_REAL_TIME_MODE) {
  98. DesiredAccess |= TRACELOG_CREATE_REALTIME;
  99. bRealTime = TRUE;
  100. }
  101. Status = WmipCheckGuidAccess( Guid, DesiredAccess );
  102. if (Status != ERROR_SUCCESS) {
  103. return Status;
  104. }
  105. //
  106. // If the user didn't specify the clock type, set the default clock type
  107. // system time.
  108. //
  109. if (LoggerInfo->Wnode.ClientContext != EVENT_TRACE_CLOCK_PERFCOUNTER &&
  110. LoggerInfo->Wnode.ClientContext != EVENT_TRACE_CLOCK_SYSTEMTIME &&
  111. LoggerInfo->Wnode.ClientContext != EVENT_TRACE_CLOCK_CPUCYCLE) {
  112. LoggerInfo->Wnode.ClientContext = EVENT_TRACE_CLOCK_SYSTEMTIME;
  113. }
  114. //
  115. // Take a reference timestamp before actually starting the logger
  116. //
  117. RefClockSys.QuadPart = WmipGetSystemTime();
  118. RefClockCycle.QuadPart = WmipGetCycleCount();
  119. Status = NtQueryPerformanceCounter(&RefClockPerf, &Frequency);
  120. if (SavedLogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) {
  121. Status = WmipSendUmLogRequest(
  122. WmiStartLoggerCode,
  123. LoggerInfo
  124. );
  125. }
  126. else if (IsKernelTrace) {
  127. //
  128. // In order to capture the process/thread rundown accurately, we need to
  129. // start kernel logger in two steps. Start logger with delay write,
  130. // do rundown from user mode and then updatelogger with filename.
  131. //
  132. WMI_LOGGER_INFORMATION DelayLoggerInfo;
  133. ULONG EnableFlags = LoggerInfo->EnableFlags;
  134. //
  135. // If it's only realtime start logger in one step
  136. //
  137. if (bRealTime && !bLogFile) {
  138. BufferSize = LoggerInfo->BufferSize * 1024;
  139. Status = WmipSendWmiKMRequest(
  140. NULL,
  141. IOCTL_WMI_START_LOGGER,
  142. LoggerInfo,
  143. LoggerInfo->Wnode.BufferSize,
  144. LoggerInfo,
  145. LoggerInfo->Wnode.BufferSize,
  146. &BufferSize,
  147. NULL
  148. );
  149. return WmipSetDosError(Status);
  150. }
  151. if (EnableFlags & EVENT_TRACE_FLAG_EXTENSION) {
  152. PTRACE_ENABLE_FLAG_EXTENSION tFlagExt;
  153. tFlagExt = (PTRACE_ENABLE_FLAG_EXTENSION)
  154. &LoggerInfo->EnableFlags;
  155. EnableFlags = *(PULONG)((PCHAR)LoggerInfo + tFlagExt->Offset);
  156. }
  157. RtlCopyMemory(&DelayLoggerInfo, LoggerInfo, sizeof(WMI_LOGGER_INFORMATION));
  158. RtlZeroMemory(&DelayLoggerInfo.LogFileName, sizeof(UNICODE_STRING) );
  159. DelayLoggerInfo.Wnode.BufferSize = sizeof(WMI_LOGGER_INFORMATION);
  160. DelayLoggerInfo.LogFileMode |= EVENT_TRACE_DELAY_OPEN_FILE_MODE;
  161. //
  162. // Since there's no filename in step 1 of StartLogger we need to mask
  163. // the NEWFILE mode to prevent kernel trying to generate a file
  164. //
  165. DelayLoggerInfo.LogFileMode &= ~EVENT_TRACE_FILE_MODE_NEWFILE;
  166. DelayLoggerInfo.EnableFlags = (EVENT_TRACE_FLAG_PROCESS & EnableFlags);
  167. DelayLoggerInfo.EnableFlags |= (EVENT_TRACE_FLAG_THREAD & EnableFlags);
  168. DelayLoggerInfo.EnableFlags |= (EVENT_TRACE_FLAG_IMAGE_LOAD & EnableFlags);
  169. BufferSize = DelayLoggerInfo.BufferSize * 1024;
  170. Status = WmipSendWmiKMRequest(
  171. NULL,
  172. IOCTL_WMI_START_LOGGER,
  173. &DelayLoggerInfo,
  174. DelayLoggerInfo.Wnode.BufferSize,
  175. &DelayLoggerInfo,
  176. DelayLoggerInfo.Wnode.BufferSize,
  177. &BufferSize,
  178. NULL
  179. );
  180. if (Status != ERROR_SUCCESS) {
  181. return Status;
  182. }
  183. LoggerInfo->Wnode.ClientContext = DelayLoggerInfo.Wnode.ClientContext;
  184. //
  185. // We need to pick up any parameter adjustment done by the kernel
  186. // here so UpdateTrace does not fail.
  187. //
  188. LoggerInfo->Wnode.HistoricalContext = DelayLoggerInfo.Wnode.HistoricalContext;
  189. LoggerInfo->MinimumBuffers = DelayLoggerInfo.MinimumBuffers;
  190. LoggerInfo->MaximumBuffers = DelayLoggerInfo.MaximumBuffers;
  191. LoggerInfo->NumberOfBuffers = DelayLoggerInfo.NumberOfBuffers;
  192. LoggerInfo->BufferSize = DelayLoggerInfo.BufferSize;
  193. LoggerInfo->AgeLimit = DelayLoggerInfo.AgeLimit;
  194. BufferSize = LoggerInfo->BufferSize * 1024;
  195. //
  196. // Add the LogHeader
  197. //
  198. LoggerInfo->Checksum = NULL;
  199. if (LoggerInfo->Wnode.ClientContext == EVENT_TRACE_CLOCK_PERFCOUNTER) {
  200. RefClock.StartPerfClock = RefClockPerf;
  201. } else if (LoggerInfo->Wnode.ClientContext == EVENT_TRACE_CLOCK_CPUCYCLE) {
  202. RefClock.StartPerfClock= RefClockCycle;
  203. } else {
  204. RefClock.StartPerfClock = RefClockSys;
  205. }
  206. RefClock.StartTime = RefClockSys;
  207. Status = WmipAddLogHeaderToLogFile(LoggerInfo, &RefClock, FALSE);
  208. if (Status == ERROR_SUCCESS) {
  209. SavedChecksum = LoggerInfo->Checksum;
  210. //
  211. // Update the logger with the filename
  212. //
  213. Status = WmipSendWmiKMRequest(
  214. NULL,
  215. IOCTL_WMI_UPDATE_LOGGER,
  216. LoggerInfo,
  217. LoggerInfo->Wnode.BufferSize,
  218. LoggerInfo,
  219. LoggerInfo->Wnode.BufferSize,
  220. &BufferSize,
  221. NULL
  222. );
  223. if (LoggerInfo->Checksum != NULL) {
  224. WmipFree(LoggerInfo->Checksum);
  225. }
  226. }
  227. if (Status != ERROR_SUCCESS) {
  228. ULONG lStatus;
  229. //
  230. // Logger must be stopped now
  231. //
  232. lStatus = WmipSendWmiKMRequest(
  233. NULL,
  234. IOCTL_WMI_STOP_LOGGER,
  235. LoggerInfo,
  236. LoggerInfo->Wnode.BufferSize,
  237. LoggerInfo,
  238. LoggerInfo->Wnode.BufferSize,
  239. &BufferSize,
  240. NULL
  241. );
  242. LoggerInfo->LogFileMode = SavedLogFileMode;
  243. return WmipSetDosError(Status);
  244. }
  245. else {
  246. if (LoggerInfo->LogFileHandle != NULL) {
  247. NtClose(LoggerInfo->LogFileHandle);
  248. LoggerInfo->LogFileHandle = NULL;
  249. }
  250. }
  251. }
  252. else {
  253. Status = WmipQueryLogger(LoggerInfo, FALSE);
  254. if (Status == ERROR_WMI_INSTANCE_NOT_FOUND) { // Logger is already running
  255. LoggerInfo->Checksum = NULL;
  256. //
  257. // Query for supported clock types. If an unsupported clock type
  258. // is specified this LoggerInfo will contain the kernel's default
  259. //
  260. Status = WmipSendWmiKMRequest(NULL,
  261. IOCTL_WMI_CLOCK_TYPE,
  262. LoggerInfo,
  263. LoggerInfo->Wnode.BufferSize,
  264. LoggerInfo,
  265. LoggerInfo->Wnode.BufferSize,
  266. &BufferSize,
  267. NULL
  268. );
  269. if (Status != ERROR_SUCCESS) {
  270. return WmipSetDosError(Status);
  271. }
  272. if (LoggerInfo->Wnode.ClientContext == EVENT_TRACE_CLOCK_PERFCOUNTER) {
  273. RefClock.StartPerfClock = RefClockPerf;
  274. } else if (LoggerInfo->Wnode.ClientContext == EVENT_TRACE_CLOCK_CPUCYCLE) {
  275. RefClock.StartPerfClock= RefClockCycle;
  276. } else {
  277. RefClock.StartPerfClock = RefClockSys;
  278. }
  279. RefClock.StartTime = RefClockSys;
  280. Status = WmipAddLogHeaderToLogFile(LoggerInfo, &RefClock, FALSE);
  281. if (Status != ERROR_SUCCESS) {
  282. return WmipSetDosError(Status);
  283. }
  284. BufferSize = LoggerInfo->BufferSize * 1024;
  285. SavedChecksum = LoggerInfo->Checksum;
  286. Status = WmipSendWmiKMRequest( // actually start the logger here
  287. NULL,
  288. IOCTL_WMI_START_LOGGER,
  289. LoggerInfo,
  290. LoggerInfo->Wnode.BufferSize,
  291. LoggerInfo,
  292. LoggerInfo->Wnode.BufferSize,
  293. &BufferSize,
  294. NULL
  295. );
  296. if (Status == ERROR_SUCCESS) {
  297. if (LoggerInfo->LogFileHandle != NULL) {
  298. NtClose(LoggerInfo->LogFileHandle);
  299. LoggerInfo->LogFileHandle = NULL;
  300. }
  301. }
  302. else if ( (Status != ERROR_MORE_DATA) &&
  303. !(LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_APPEND)) {
  304. if (LoggerInfo->LogFileName.Buffer != NULL) {
  305. DeleteFileW(LoggerInfo->LogFileName.Buffer);
  306. }
  307. }
  308. if (SavedChecksum != NULL) {
  309. WmipFree(SavedChecksum);
  310. }
  311. }
  312. else {
  313. if ((Status == ERROR_SUCCESS) ||
  314. (Status == ERROR_MORE_DATA))
  315. Status = ERROR_ALREADY_EXISTS;
  316. }
  317. }
  318. //
  319. // Restore the LogFileMode
  320. //
  321. LoggerInfo->LogFileMode = SavedLogFileMode;
  322. return WmipSetDosError(Status);
  323. }
  324. ULONG
  325. WmipFinalizeLogFileHeader(
  326. IN PWMI_LOGGER_INFORMATION LoggerInfo
  327. )
  328. {
  329. ULONG Status = ERROR_SUCCESS;
  330. ULONG ErrorCode = ERROR_SUCCESS;
  331. HANDLE LogFile = INVALID_HANDLE_VALUE;
  332. LARGE_INTEGER CurrentTime;
  333. ULONG BuffersWritten;
  334. WMI_LOGGER_CONTEXT Logger;
  335. IO_STATUS_BLOCK IoStatus;
  336. FILE_POSITION_INFORMATION FileInfo;
  337. FILE_STANDARD_INFORMATION FileSize;
  338. PWMI_BUFFER_HEADER Buffer; // need to initialize buffer first
  339. SYSTEM_BASIC_INFORMATION SystemInfo;
  340. ULONG EnableFlags;
  341. ULONG IsGlobalForKernel = FALSE;
  342. USHORT LoggerId = 0;
  343. RtlZeroMemory(&Logger, sizeof(WMI_LOGGER_CONTEXT));
  344. Logger.BufferSpace = NULL;
  345. if (LoggerInfo->LogFileName.Length > 0 ) {
  346. // open the file for writing synchronously for the logger
  347. // others may want to read it as well.
  348. //
  349. LogFile = CreateFileW(
  350. (LPWSTR)LoggerInfo->LogFileName.Buffer,
  351. GENERIC_READ | GENERIC_WRITE,
  352. FILE_SHARE_READ,
  353. NULL,
  354. OPEN_EXISTING,
  355. FILE_ATTRIBUTE_NORMAL,
  356. NULL
  357. );
  358. if (LogFile == INVALID_HANDLE_VALUE) {
  359. ErrorCode = WmipSetDosError(GetLastError());
  360. goto cleanup;
  361. }
  362. // Truncate the file size if in PREALLOCATE mode
  363. if (LoggerInfo->MaximumFileSize &&
  364. (LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_PREALLOCATE)) {
  365. // Do this only when we haven't reach the max file size
  366. if (LoggerInfo->MaximumFileSize > (((ULONGLONG)LoggerInfo->BuffersWritten * (ULONGLONG)LoggerInfo->BufferSize) / 1024)) {
  367. IO_STATUS_BLOCK IoStatusBlock;
  368. FILE_END_OF_FILE_INFORMATION EOFInfo;
  369. EOFInfo.EndOfFile.QuadPart = (ULONGLONG)LoggerInfo->BuffersWritten * (ULONGLONG)LoggerInfo->BufferSize * 1024;
  370. // Checksum64 in WMI_LOGGER_INFORMATION has the number of GuidMap buffers.
  371. EOFInfo.EndOfFile.QuadPart += LoggerInfo->Checksum64 * (ULONGLONG)LoggerInfo->BufferSize * 1024;
  372. Status = NtSetInformationFile(LogFile,
  373. &IoStatusBlock,
  374. &EOFInfo,
  375. sizeof(FILE_END_OF_FILE_INFORMATION),
  376. FileEndOfFileInformation);
  377. if (!NT_SUCCESS(Status)) {
  378. NtClose(LogFile);
  379. ErrorCode = WmipNtStatusToDosError(Status);
  380. goto cleanup;
  381. }
  382. }
  383. }
  384. Logger.BuffersWritten = LoggerInfo->BuffersWritten;
  385. Logger.BufferSpace = WmipAlloc(LoggerInfo->BufferSize * 1024);
  386. if (Logger.BufferSpace == NULL) {
  387. ErrorCode = WmipSetDosError(ERROR_NOT_ENOUGH_MEMORY);
  388. goto cleanup;
  389. }
  390. Buffer = (PWMI_BUFFER_HEADER) Logger.BufferSpace;
  391. RtlZeroMemory(Buffer, LoggerInfo->BufferSize * 1024);
  392. Buffer->Wnode.BufferSize = LoggerInfo->BufferSize * 1024;
  393. Buffer->ClientContext.Alignment = (UCHAR)WmiTraceAlignment;
  394. Buffer->EventsLost = 0;
  395. Buffer->Offset = sizeof(WMI_BUFFER_HEADER);
  396. Buffer->Wnode.Guid = LoggerInfo->Wnode.Guid;
  397. Status = NtQuerySystemInformation(
  398. SystemBasicInformation,
  399. &SystemInfo, sizeof (SystemInfo), NULL);
  400. if (!NT_SUCCESS(Status)) {
  401. ErrorCode = WmipNtStatusToDosError(Status);
  402. goto cleanup;
  403. }
  404. Logger.TimerResolution = SystemInfo.TimerResolution;
  405. Logger.LogFileHandle = LogFile;
  406. Logger.BufferSize = LoggerInfo->BufferSize * 1024;
  407. // For Circular LogFile the process rundown data is appended at the
  408. // last buffer written and not to the end of file.
  409. //
  410. Status = NtQueryInformationFile(
  411. LogFile,
  412. &IoStatus,
  413. &FileSize,
  414. sizeof(FILE_STANDARD_INFORMATION),
  415. FileStandardInformation
  416. );
  417. if (!NT_SUCCESS(Status)) {
  418. ErrorCode = WmipNtStatusToDosError(Status);
  419. goto cleanup;
  420. }
  421. //
  422. // For Kernel Boot Traces, we need to do the Rundown.
  423. // configuration at this time.
  424. // 1. The Logger ID is GLOBAL_LOGGER_ID
  425. // 2. The LoggerName is NT_KERNEL_LOGGER
  426. //
  427. // The First condition is true for any GlobalLogger but
  428. // condition 2 is TRUE only when it is collecting kernel traces.
  429. //
  430. LoggerId = WmiGetLoggerId (LoggerInfo->Wnode.HistoricalContext);
  431. if ( (LoggerId == WMI_GLOBAL_LOGGER_ID) &&
  432. (LoggerInfo->LoggerName.Length > 0) &&
  433. (LoggerInfo->LoggerName.Buffer != NULL) &&
  434. (!wcscmp(LoggerInfo->LoggerName.Buffer, KERNEL_LOGGER_NAMEW))
  435. ) {
  436. IsGlobalForKernel = TRUE;
  437. }
  438. if ( (IsEqualGUID(&LoggerInfo->Wnode.Guid, &SystemTraceControlGuid)) ||
  439. IsGlobalForKernel ) {
  440. if (IsGlobalForKernel) {
  441. ULONG CpuSpeed;
  442. ULONG CpuNum = 0;
  443. //
  444. // For boot traces we need to re-set the CPU Speed in the
  445. // log file header as it is not available in the registry
  446. // when the log file header is first created.
  447. //
  448. if (NT_SUCCESS(WmipGetCpuSpeed(&CpuNum, &CpuSpeed))) {
  449. FileInfo.CurrentByteOffset.QuadPart =
  450. LOGFILE_FIELD_OFFSET(CpuSpeedInMHz);
  451. Status = NtSetInformationFile(
  452. LogFile,
  453. &IoStatus,
  454. &FileInfo,
  455. sizeof(FILE_POSITION_INFORMATION),
  456. FilePositionInformation
  457. );
  458. if (!NT_SUCCESS(Status)) {
  459. ErrorCode = WmipNtStatusToDosError(Status);
  460. goto cleanup;
  461. }
  462. Status = NtWriteFile(
  463. LogFile,
  464. NULL,
  465. NULL,
  466. NULL,
  467. &IoStatus,
  468. &CpuSpeed,
  469. sizeof(CpuSpeed),
  470. NULL,
  471. NULL
  472. );
  473. //
  474. // I don't like this. However, write failures are never a
  475. // failure case for the log file so I'll follow their
  476. // trend... for now.
  477. //
  478. if (NT_SUCCESS(Status)) {
  479. NtFlushBuffersFile(Logger.LogFileHandle, &IoStatus);
  480. }
  481. }
  482. }
  483. if (LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_CIRCULAR) {
  484. ULONG BufferSize = LoggerInfo->BufferSize; // in KB
  485. ULONG BuffersWritten = LoggerInfo->BuffersWritten;
  486. ULONG maxBuffers = (LoggerInfo->MaximumFileSize * 1024) / BufferSize;
  487. ULONG LastBuffer;
  488. ULONG StartBuffers;
  489. FileInfo.CurrentByteOffset.QuadPart =
  490. LOGFILE_FIELD_OFFSET(StartBuffers);
  491. Status = NtSetInformationFile(
  492. LogFile,
  493. &IoStatus,
  494. &FileInfo,
  495. sizeof(FILE_POSITION_INFORMATION),
  496. FilePositionInformation
  497. );
  498. if (!NT_SUCCESS(Status)) {
  499. ErrorCode = WmipNtStatusToDosError(Status);
  500. goto cleanup;
  501. }
  502. Status = NtReadFile(
  503. LogFile,
  504. NULL,
  505. NULL,
  506. NULL,
  507. &IoStatus,
  508. &StartBuffers,
  509. sizeof(ULONG),
  510. NULL,
  511. NULL
  512. );
  513. if (!NT_SUCCESS(Status)) {
  514. ErrorCode = WmipNtStatusToDosError(Status);
  515. goto cleanup;
  516. }
  517. LastBuffer = (maxBuffers > StartBuffers) ?
  518. (StartBuffers + (BuffersWritten - StartBuffers)
  519. % (maxBuffers - StartBuffers))
  520. : 0;
  521. FileInfo.CurrentByteOffset.QuadPart = LastBuffer *
  522. BufferSize * 1024;
  523. }
  524. else {
  525. FileInfo.CurrentByteOffset = FileSize.EndOfFile;
  526. }
  527. Status = NtSetInformationFile(
  528. LogFile,
  529. &IoStatus,
  530. &FileInfo,
  531. sizeof(FILE_POSITION_INFORMATION),
  532. FilePositionInformation
  533. );
  534. if (!NT_SUCCESS(Status)) {
  535. ErrorCode = WmipNtStatusToDosError(Status);
  536. goto cleanup;
  537. }
  538. EnableFlags = LoggerInfo->EnableFlags;
  539. if (EnableFlags & EVENT_TRACE_FLAG_EXTENSION) {
  540. PTRACE_ENABLE_FLAG_EXTENSION tFlagExt;
  541. tFlagExt = (PTRACE_ENABLE_FLAG_EXTENSION)
  542. &LoggerInfo->EnableFlags;
  543. if (LoggerInfo->Wnode.BufferSize >= (tFlagExt->Offset + sizeof(ULONG)) ) {
  544. EnableFlags = *(PULONG)((PCHAR)LoggerInfo + tFlagExt->Offset);
  545. }
  546. else {
  547. EnableFlags = 0; // Should not happen.
  548. }
  549. }
  550. Logger.UsePerfClock = LoggerInfo->Wnode.ClientContext;
  551. WmipProcessRunDown(&Logger, FALSE, EnableFlags);
  552. if (IsGlobalForKernel) {
  553. WmipDumpHardwareConfig(&Logger);
  554. }
  555. {
  556. PWMI_BUFFER_HEADER Buffer1 =
  557. (PWMI_BUFFER_HEADER) Logger.BufferSpace;
  558. if (Buffer1->Offset < Logger.BufferSize) {
  559. RtlFillMemory(
  560. (char *) Logger.BufferSpace + Buffer1->Offset,
  561. Logger.BufferSize - Buffer1->Offset,
  562. 0xFF);
  563. }
  564. }
  565. Status = NtWriteFile(
  566. LogFile,
  567. NULL,
  568. NULL,
  569. NULL,
  570. &IoStatus,
  571. Logger.BufferSpace,
  572. Logger.BufferSize,
  573. NULL,
  574. NULL);
  575. if (NT_SUCCESS(Status)) {
  576. NtFlushBuffersFile(Logger.LogFileHandle, &IoStatus);
  577. Logger.BuffersWritten++;
  578. }
  579. }
  580. else { // For Application Traces, need to dump the guidmaps again.
  581. // Set the FilePointer to end of file so that Rundown data may be appended.
  582. //
  583. FileInfo.CurrentByteOffset = FileSize.EndOfFile;
  584. Status = NtSetInformationFile(
  585. LogFile,
  586. &IoStatus,
  587. &FileInfo,
  588. sizeof(FILE_POSITION_INFORMATION),
  589. FilePositionInformation
  590. );
  591. if (!NT_SUCCESS(Status)) {
  592. ErrorCode = WmipNtStatusToDosError(Status);
  593. goto cleanup;
  594. }
  595. // Dump the Guid Maps once more at the End.
  596. //
  597. Buffer->EventsLost = 0;
  598. Buffer->Offset = sizeof(WMI_BUFFER_HEADER);
  599. BuffersWritten = Logger.BuffersWritten;
  600. if (WmipDumpGuidMaps(&Logger, NULL, FALSE) > 0) {
  601. if (Buffer->Offset < Logger.BufferSize) {
  602. RtlFillMemory(
  603. (char *) Logger.BufferSpace + Buffer->Offset,
  604. Logger.BufferSize - Buffer->Offset,
  605. 0xFF);
  606. }
  607. Status = NtWriteFile(
  608. LogFile,
  609. NULL,
  610. NULL,
  611. NULL,
  612. &IoStatus,
  613. Logger.BufferSpace,
  614. Logger.BufferSize,
  615. NULL,
  616. NULL);
  617. if (NT_SUCCESS(Status)) {
  618. NtFlushBuffersFile(Logger.LogFileHandle, &IoStatus);
  619. Logger.BuffersWritten = BuffersWritten;
  620. }
  621. }
  622. }
  623. // TODO: should use memory-mapped file
  624. // Update the EndTime stamp field in LogFile. No Need to
  625. // to do it if it's Relogged File. The old logfile
  626. // header already has the correct value.
  627. //
  628. if ( !(LoggerInfo->LogFileMode & EVENT_TRACE_RELOG_MODE) ) {
  629. FileInfo.CurrentByteOffset.QuadPart =
  630. LOGFILE_FIELD_OFFSET(EndTime);
  631. Status = NtSetInformationFile(
  632. LogFile,
  633. &IoStatus,
  634. &FileInfo,
  635. sizeof(FILE_POSITION_INFORMATION),
  636. FilePositionInformation
  637. );
  638. if (!NT_SUCCESS(Status)) {
  639. ErrorCode = WmipNtStatusToDosError(Status);
  640. goto cleanup;
  641. }
  642. // End Time is always wallclock time.
  643. //
  644. CurrentTime.QuadPart = WmipGetSystemTime();
  645. Status = NtWriteFile(
  646. LogFile,
  647. NULL,
  648. NULL,
  649. NULL,
  650. &IoStatus,
  651. &CurrentTime,
  652. sizeof(ULONGLONG),
  653. NULL,
  654. NULL
  655. );
  656. if (NT_SUCCESS(Status)) {
  657. NtFlushBuffersFile(Logger.LogFileHandle, &IoStatus);
  658. }
  659. }
  660. // Update the Number of Buffers Written field in the header
  661. //
  662. FileInfo.CurrentByteOffset.QuadPart =
  663. LOGFILE_FIELD_OFFSET(BuffersWritten);
  664. Status = NtSetInformationFile(
  665. LogFile,
  666. &IoStatus,
  667. &FileInfo,
  668. sizeof(FILE_POSITION_INFORMATION),
  669. FilePositionInformation
  670. );
  671. if (!NT_SUCCESS(Status)) {
  672. ErrorCode = WmipNtStatusToDosError(Status);
  673. goto cleanup;
  674. }
  675. Status = NtWriteFile(
  676. LogFile,
  677. NULL,
  678. NULL,
  679. NULL,
  680. &IoStatus,
  681. &Logger.BuffersWritten,
  682. sizeof(ULONG),
  683. NULL,
  684. NULL
  685. );
  686. if (NT_SUCCESS(Status)) {
  687. NtFlushBuffersFile(Logger.LogFileHandle, &IoStatus);
  688. }
  689. ErrorCode = RtlNtStatusToDosError(Status);
  690. LoggerInfo->BuffersWritten = Logger.BuffersWritten;
  691. //
  692. // Write the BuffersLost information into the logfile
  693. //
  694. FileInfo.CurrentByteOffset.QuadPart =
  695. LOGFILE_FIELD_OFFSET(BuffersLost);
  696. Status = NtSetInformationFile(
  697. LogFile,
  698. &IoStatus,
  699. &FileInfo,
  700. sizeof(FILE_POSITION_INFORMATION),
  701. FilePositionInformation
  702. );
  703. if (!NT_SUCCESS(Status)) {
  704. ErrorCode = WmipNtStatusToDosError(Status);
  705. goto cleanup;
  706. }
  707. Status = NtWriteFile(
  708. LogFile,
  709. NULL,
  710. NULL,
  711. NULL,
  712. &IoStatus,
  713. &LoggerInfo->LogBuffersLost,
  714. sizeof(ULONG),
  715. NULL,
  716. NULL
  717. );
  718. if (NT_SUCCESS(Status)) {
  719. NtFlushBuffersFile(Logger.LogFileHandle, &IoStatus);
  720. }
  721. //
  722. // Write the EventsLost information into the logfile
  723. //
  724. //
  725. // No need to update EventsLost for Relogged File. Old LogFileHeader
  726. // already has the right value.
  727. //
  728. if ( !(LoggerInfo->LogFileMode & EVENT_TRACE_RELOG_MODE) ) {
  729. FileInfo.CurrentByteOffset.QuadPart =
  730. LOGFILE_FIELD_OFFSET(EventsLost);
  731. Status = NtSetInformationFile(
  732. LogFile,
  733. &IoStatus,
  734. &FileInfo,
  735. sizeof(FILE_POSITION_INFORMATION),
  736. FilePositionInformation
  737. );
  738. if (!NT_SUCCESS(Status)) {
  739. ErrorCode = WmipNtStatusToDosError(Status);
  740. goto cleanup;
  741. }
  742. Status = NtWriteFile(
  743. LogFile,
  744. NULL,
  745. NULL,
  746. NULL,
  747. &IoStatus,
  748. &LoggerInfo->EventsLost,
  749. sizeof(ULONG),
  750. NULL,
  751. NULL
  752. );
  753. if (NT_SUCCESS(Status)) {
  754. NtFlushBuffersFile(Logger.LogFileHandle, &IoStatus);
  755. }
  756. }
  757. }
  758. cleanup:
  759. if (LogFile != INVALID_HANDLE_VALUE) {
  760. NtClose(LogFile);
  761. }
  762. if (Logger.BufferSpace != NULL) {
  763. WmipFree(Logger.BufferSpace);
  764. }
  765. return WmipSetDosError(ErrorCode);
  766. }
  767. ULONG
  768. WmipStopLogger(
  769. IN OUT PWMI_LOGGER_INFORMATION LoggerInfo
  770. )
  771. /*++
  772. Routine Description:
  773. This is the actual routine to communicate with the kernel to stop
  774. the logger. All the properties of the logger will be returned in LoggerInfo.
  775. Arguments:
  776. LoggerInfo The actual parameters to be passed to and return from
  777. kernel.
  778. Return Value:
  779. The status of performing the action requested.
  780. --*/
  781. {
  782. ULONG ErrorCode, ReturnSize;
  783. PTRACE_ENABLE_CONTEXT pContext;
  784. if (LoggerInfo == NULL)
  785. return WmipSetDosError(ERROR_INVALID_PARAMETER);
  786. if (LoggerInfo->Wnode.BufferSize < sizeof(WMI_LOGGER_INFORMATION))
  787. return WmipSetDosError(ERROR_INVALID_PARAMETER);
  788. if ( !(LoggerInfo->Wnode.Flags & WNODE_FLAG_TRACED_GUID) )
  789. return WmipSetDosError(ERROR_INVALID_PARAMETER);
  790. //
  791. //Check For Heap and Crit Sec Guid.
  792. //
  793. if( IsEqualGUID(&HeapGuid,&LoggerInfo->Wnode.Guid)
  794. || IsEqualGUID(&CritSecGuid,&LoggerInfo->Wnode.Guid)
  795. ){
  796. WMINTDLLLOGGERINFO NtdllLoggerInfo;
  797. ULONG BufferSize;
  798. LoggerInfo->Wnode.BufferSize = 0;
  799. RtlCopyMemory(&LoggerInfo->Wnode.Guid, &NtdllTraceGuid, sizeof(GUID));
  800. NtdllLoggerInfo.LoggerInfo = LoggerInfo;
  801. NtdllLoggerInfo.IsGet = FALSE;
  802. ErrorCode = WmipSendWmiKMRequest(
  803. NULL,
  804. IOCTL_WMI_NTDLL_LOGGERINFO,
  805. &NtdllLoggerInfo,
  806. sizeof(WMINTDLLLOGGERINFO),
  807. &NtdllLoggerInfo,
  808. sizeof(WMINTDLLLOGGERINFO),
  809. &BufferSize,
  810. NULL
  811. );
  812. return WmipSetDosError(ErrorCode);
  813. }
  814. pContext = (PTRACE_ENABLE_CONTEXT) & LoggerInfo->Wnode.HistoricalContext;
  815. if ( (pContext->InternalFlag != 0)
  816. && (pContext->InternalFlag != EVENT_TRACE_INTERNAL_FLAG_PRIVATE)) {
  817. // Currently only one possible InternalFlag value. This will filter
  818. // out some bogus LoggerHandle
  819. //
  820. return WmipSetDosError(ERROR_INVALID_HANDLE);
  821. }
  822. if (LoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) {
  823. ErrorCode = WmipSendUmLogRequest(WmiStopLoggerCode, LoggerInfo);
  824. pContext->InternalFlag |= EVENT_TRACE_INTERNAL_FLAG_PRIVATE;
  825. pContext->LoggerId = 1;
  826. }
  827. else {
  828. ErrorCode = WmipSendWmiKMRequest(
  829. NULL,
  830. IOCTL_WMI_STOP_LOGGER,
  831. LoggerInfo,
  832. LoggerInfo->Wnode.BufferSize,
  833. LoggerInfo,
  834. LoggerInfo->Wnode.BufferSize,
  835. &ReturnSize,
  836. NULL
  837. );
  838. //
  839. // if logging to a file, then update the EndTime, BuffersWritten and do
  840. // process rundown for kernel trace.
  841. //
  842. if (ErrorCode == ERROR_SUCCESS) {
  843. ErrorCode = WmipFinalizeLogFileHeader(LoggerInfo);
  844. }
  845. }
  846. return WmipSetDosError(ErrorCode);
  847. }
  848. ULONG
  849. WmipQueryLogger(
  850. IN OUT PWMI_LOGGER_INFORMATION LoggerInfo,
  851. IN ULONG Update
  852. )
  853. /*++
  854. Routine Description:
  855. This is the actual routine to communicate with the kernel to query
  856. the logger. All the properties of the logger will be returned in LoggerInfo.
  857. Arguments:
  858. LoggerInfo The actual parameters to be passed to and return from
  859. kernel.
  860. Return Value:
  861. The status of performing the action requested.
  862. --*/
  863. {
  864. ULONG Status, ReturnSize;
  865. HANDLE LogFileHandle = NULL;
  866. PTRACE_ENABLE_CONTEXT pContext;
  867. BOOLEAN bAddAppendFlag = FALSE;
  868. ULONG SavedLogFileMode;
  869. if (LoggerInfo == NULL)
  870. return WmipSetDosError(ERROR_INVALID_PARAMETER);
  871. if (LoggerInfo->Wnode.BufferSize < sizeof(WMI_LOGGER_INFORMATION))
  872. return WmipSetDosError(ERROR_INVALID_PARAMETER);
  873. if ( !(LoggerInfo->Wnode.Flags & WNODE_FLAG_TRACED_GUID) )
  874. return WmipSetDosError(ERROR_INVALID_PARAMETER);
  875. LoggerInfo->Checksum = NULL;
  876. LoggerInfo->LogFileHandle = NULL;
  877. pContext = (PTRACE_ENABLE_CONTEXT) &LoggerInfo->Wnode.HistoricalContext;
  878. if ( (pContext->InternalFlag != 0)
  879. && (pContext->InternalFlag != EVENT_TRACE_INTERNAL_FLAG_PRIVATE)) {
  880. // Currently only one possible InternalFlag value. This will filter
  881. // out some bogus LoggerHandle
  882. //
  883. return WmipSetDosError(ERROR_INVALID_HANDLE);
  884. }
  885. //
  886. // If UPDATE and a new logfile is given throw in the LogFileHeader
  887. //
  888. if ( Update
  889. && LoggerInfo->LogFileName.Length > 0
  890. && !( (LoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE)
  891. || (pContext->InternalFlag & EVENT_TRACE_INTERNAL_FLAG_PRIVATE))) {
  892. Status = WmipAddLogHeaderToLogFile(LoggerInfo, NULL, Update);
  893. if (Status != ERROR_SUCCESS) {
  894. return WmipSetDosError(Status);
  895. }
  896. LogFileHandle = LoggerInfo->LogFileHandle;
  897. bAddAppendFlag = TRUE;
  898. //
  899. // If we are switching to a new file, make sure it is append mode
  900. //
  901. SavedLogFileMode = LoggerInfo->LogFileMode;
  902. }
  903. if (LoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE ||
  904. pContext->InternalFlag & EVENT_TRACE_INTERNAL_FLAG_PRIVATE) {
  905. pContext->InternalFlag |= EVENT_TRACE_INTERNAL_FLAG_PRIVATE;
  906. pContext->LoggerId = 1;
  907. Status = WmipSendUmLogRequest(
  908. (Update) ? (WmiUpdateLoggerCode) : (WmiQueryLoggerCode),
  909. LoggerInfo
  910. );
  911. }
  912. else {
  913. Status = WmipSendWmiKMRequest(
  914. NULL,
  915. (Update ? IOCTL_WMI_UPDATE_LOGGER : IOCTL_WMI_QUERY_LOGGER),
  916. LoggerInfo,
  917. LoggerInfo->Wnode.BufferSize,
  918. LoggerInfo,
  919. LoggerInfo->Wnode.BufferSize,
  920. &ReturnSize,
  921. NULL
  922. );
  923. if (LoggerInfo->Checksum != NULL) {
  924. WmipFree(LoggerInfo->Checksum);
  925. }
  926. }
  927. if (bAddAppendFlag) {
  928. LoggerInfo->LogFileMode = SavedLogFileMode;
  929. }
  930. return WmipSetDosError(Status);
  931. }
  932. PVOID
  933. WmipGetTraceBuffer(
  934. IN PWMI_LOGGER_CONTEXT Logger,
  935. IN PSYSTEM_THREAD_INFORMATION pThread,
  936. IN ULONG GroupType,
  937. IN ULONG RequiredSize
  938. )
  939. {
  940. PSYSTEM_TRACE_HEADER Header;
  941. PWMI_BUFFER_HEADER Buffer;
  942. THREAD_BASIC_INFORMATION ThreadInfo;
  943. KERNEL_USER_TIMES ThreadCpu;
  944. NTSTATUS Status;
  945. ULONG BytesUsed;
  946. PCLIENT_ID Cid;
  947. RequiredSize += sizeof (SYSTEM_TRACE_HEADER); // add in header
  948. RequiredSize = (ULONG) ALIGN_TO_POWER2(RequiredSize, WmiTraceAlignment);
  949. Buffer = (PWMI_BUFFER_HEADER) Logger->BufferSpace;
  950. if (RequiredSize > Logger->BufferSize - sizeof(WMI_BUFFER_HEADER)) {
  951. WmipSetDosError(ERROR_BUFFER_OVERFLOW);
  952. return NULL;
  953. }
  954. if (RequiredSize > (Logger->BufferSize - Buffer->Offset)) {
  955. ULONG Status;
  956. IO_STATUS_BLOCK IoStatus;
  957. if (Buffer->Offset < Logger->BufferSize) {
  958. RtlFillMemory(
  959. (char *) Buffer + Buffer->Offset,
  960. Logger->BufferSize - Buffer->Offset,
  961. 0xFF);
  962. }
  963. Status = NtWriteFile(
  964. Logger->LogFileHandle,
  965. NULL,
  966. NULL,
  967. NULL,
  968. &IoStatus,
  969. Buffer,
  970. Logger->BufferSize,
  971. NULL,
  972. NULL);
  973. Buffer->EventsLost = 0;
  974. Buffer->Offset = sizeof(WMI_BUFFER_HEADER);
  975. if (!NT_SUCCESS(Status)) {
  976. return NULL;
  977. }
  978. Logger->BuffersWritten++;
  979. }
  980. Header = (PSYSTEM_TRACE_HEADER) ((char*)Buffer + Buffer->Offset);
  981. if (Logger->UsePerfClock == EVENT_TRACE_CLOCK_PERFCOUNTER) {
  982. LARGE_INTEGER Frequency;
  983. ULONGLONG Counter = 0;
  984. Status = NtQueryPerformanceCounter((PLARGE_INTEGER)&Counter,
  985. &Frequency);
  986. Header->SystemTime.QuadPart = Counter;
  987. } else if (Logger->UsePerfClock == EVENT_TRACE_CLOCK_CPUCYCLE) {
  988. Header->SystemTime.QuadPart = WmipGetCycleCount();
  989. } else {
  990. Header->SystemTime.QuadPart = WmipGetSystemTime();
  991. }
  992. Header->Header = (GroupType << 16) + RequiredSize;
  993. Header->Marker = SYSTEM_TRACE_MARKER;
  994. if (pThread == NULL) {
  995. Status = NtQueryInformationThread(
  996. NtCurrentThread(),
  997. ThreadBasicInformation,
  998. &ThreadInfo,
  999. sizeof ThreadInfo, NULL);
  1000. if (NT_SUCCESS(Status)) {
  1001. Cid = &ThreadInfo.ClientId;
  1002. Header->ThreadId = HandleToUlong(Cid->UniqueThread);
  1003. Header->ProcessId = HandleToUlong(Cid->UniqueProcess);
  1004. }
  1005. Status = NtQueryInformationThread(
  1006. NtCurrentThread(),
  1007. ThreadTimes,
  1008. &ThreadCpu, sizeof ThreadCpu, NULL);
  1009. if (NT_SUCCESS(Status)) {
  1010. Header->KernelTime = (ULONG) (ThreadCpu.KernelTime.QuadPart
  1011. / Logger->TimerResolution);
  1012. Header->UserTime = (ULONG) (ThreadCpu.UserTime.QuadPart
  1013. / Logger->TimerResolution);
  1014. }
  1015. }
  1016. else {
  1017. Cid = &pThread->ClientId;
  1018. Header->ThreadId = HandleToUlong(Cid->UniqueThread);
  1019. Header->ProcessId = HandleToUlong(Cid->UniqueProcess);
  1020. Header->KernelTime = (ULONG) (pThread->KernelTime.QuadPart
  1021. / Logger->TimerResolution);
  1022. Header->UserTime = (ULONG) (pThread->UserTime.QuadPart
  1023. / Logger->TimerResolution);
  1024. }
  1025. Buffer->Offset += RequiredSize;
  1026. // If there is room, throw in a end of buffer marker.
  1027. BytesUsed = Buffer->Offset;
  1028. if ( BytesUsed <= (Logger->BufferSize-sizeof(ULONG)) ) {
  1029. *((long*)((char*)Buffer+Buffer->Offset)) = -1;
  1030. }
  1031. return (PVOID) ( (char*) Header + sizeof(SYSTEM_TRACE_HEADER) );
  1032. }
  1033. VOID
  1034. WmipCopyPropertiesToInfo(
  1035. IN PEVENT_TRACE_PROPERTIES Properties,
  1036. IN PWMI_LOGGER_INFORMATION Info
  1037. )
  1038. {
  1039. ULONG SavedBufferSize = Info->Wnode.BufferSize;
  1040. RtlCopyMemory(&Info->Wnode, &Properties->Wnode, sizeof(WNODE_HEADER));
  1041. Info->Wnode.BufferSize = SavedBufferSize;
  1042. Info->BufferSize = Properties->BufferSize;
  1043. Info->MinimumBuffers = Properties->MinimumBuffers;
  1044. Info->MaximumBuffers = Properties->MaximumBuffers;
  1045. Info->NumberOfBuffers = Properties->NumberOfBuffers;
  1046. Info->FreeBuffers = Properties->FreeBuffers;
  1047. Info->EventsLost = Properties->EventsLost;
  1048. Info->BuffersWritten = Properties->BuffersWritten;
  1049. Info->LoggerThreadId = Properties->LoggerThreadId;
  1050. Info->MaximumFileSize = Properties->MaximumFileSize;
  1051. Info->EnableFlags = Properties->EnableFlags;
  1052. Info->LogFileMode = Properties->LogFileMode;
  1053. Info->FlushTimer = Properties->FlushTimer;
  1054. Info->LogBuffersLost = Properties->LogBuffersLost;
  1055. Info->AgeLimit = Properties->AgeLimit;
  1056. Info->RealTimeBuffersLost = Properties->RealTimeBuffersLost;
  1057. }
  1058. VOID
  1059. WmipCopyInfoToProperties(
  1060. IN PWMI_LOGGER_INFORMATION Info,
  1061. IN PEVENT_TRACE_PROPERTIES Properties
  1062. )
  1063. {
  1064. ULONG SavedSize = Properties->Wnode.BufferSize;
  1065. RtlCopyMemory(&Properties->Wnode, &Info->Wnode, sizeof(WNODE_HEADER));
  1066. Properties->Wnode.BufferSize = SavedSize;
  1067. Properties->BufferSize = Info->BufferSize;
  1068. Properties->MinimumBuffers = Info->MinimumBuffers;
  1069. Properties->MaximumBuffers = Info->MaximumBuffers;
  1070. Properties->NumberOfBuffers = Info->NumberOfBuffers;
  1071. Properties->FreeBuffers = Info->FreeBuffers;
  1072. Properties->EventsLost = Info->EventsLost;
  1073. Properties->BuffersWritten = Info->BuffersWritten;
  1074. Properties->LoggerThreadId = Info->LoggerThreadId;
  1075. Properties->MaximumFileSize = Info->MaximumFileSize;
  1076. Properties->EnableFlags = Info->EnableFlags;
  1077. Properties->LogFileMode = Info->LogFileMode;
  1078. Properties->FlushTimer = Info->FlushTimer;
  1079. Properties->LogBuffersLost = Info->LogBuffersLost;
  1080. Properties->AgeLimit = Info->AgeLimit;
  1081. Properties->RealTimeBuffersLost = Info->RealTimeBuffersLost;
  1082. }
  1083. NTSTATUS
  1084. WmipThreadRunDown(
  1085. IN PWMI_LOGGER_CONTEXT Logger,
  1086. IN PSYSTEM_PROCESS_INFORMATION pProcessInfo,
  1087. IN ULONG StartFlag,
  1088. IN BOOLEAN bExtended
  1089. )
  1090. {
  1091. PSYSTEM_THREAD_INFORMATION pThreadInfo;
  1092. ULONG GroupType;
  1093. ULONG i;
  1094. ULONG Size;
  1095. ULONG SystemThreadInfoSize;
  1096. PWMI_EXTENDED_THREAD_INFORMATION ThreadInfo;
  1097. pThreadInfo = (PSYSTEM_THREAD_INFORMATION) (pProcessInfo+1);
  1098. GroupType = EVENT_TRACE_GROUP_THREAD +
  1099. ((StartFlag) ? EVENT_TRACE_TYPE_DC_START
  1100. : EVENT_TRACE_TYPE_DC_END);
  1101. Size = sizeof(WMI_EXTENDED_THREAD_INFORMATION);
  1102. SystemThreadInfoSize = (bExtended) ? sizeof(SYSTEM_EXTENDED_THREAD_INFORMATION)
  1103. : sizeof(SYSTEM_THREAD_INFORMATION);
  1104. for (i=0; i < pProcessInfo->NumberOfThreads; i++) {
  1105. if (pThreadInfo == NULL)
  1106. break;
  1107. ThreadInfo = (PWMI_EXTENDED_THREAD_INFORMATION)
  1108. WmipGetTraceBuffer( Logger,
  1109. pThreadInfo,
  1110. GroupType,
  1111. Size );
  1112. if (ThreadInfo) {
  1113. ThreadInfo->ProcessId =
  1114. HandleToUlong(pThreadInfo->ClientId.UniqueProcess);
  1115. ThreadInfo->ThreadId =
  1116. HandleToUlong(pThreadInfo->ClientId.UniqueThread);
  1117. if (bExtended) {
  1118. PSYSTEM_EXTENDED_THREAD_INFORMATION pExtThreadInfo;
  1119. pExtThreadInfo = (PSYSTEM_EXTENDED_THREAD_INFORMATION) pThreadInfo;
  1120. ThreadInfo->StackBase = pExtThreadInfo->StackBase;
  1121. ThreadInfo->StackLimit = pExtThreadInfo->StackLimit;
  1122. ThreadInfo->StartAddr = pExtThreadInfo->ThreadInfo.StartAddress;
  1123. ThreadInfo->Win32StartAddr = pExtThreadInfo->Win32StartAddress;
  1124. ThreadInfo->UserStackBase = NULL;
  1125. ThreadInfo->UserStackLimit = NULL;
  1126. ThreadInfo->WaitMode = -1;
  1127. }
  1128. else {
  1129. ThreadInfo->StackBase = NULL;
  1130. ThreadInfo->StackLimit = NULL;
  1131. ThreadInfo->StartAddr = NULL;
  1132. ThreadInfo->Win32StartAddr = NULL;
  1133. ThreadInfo->UserStackBase = NULL;
  1134. ThreadInfo->UserStackLimit = NULL;
  1135. ThreadInfo->WaitMode = -1;
  1136. }
  1137. }
  1138. pThreadInfo = (PSYSTEM_THREAD_INFORMATION)( (char*)pThreadInfo + SystemThreadInfoSize );
  1139. }
  1140. return STATUS_SUCCESS;
  1141. }
  1142. void
  1143. WmipLogImageLoadEvent(
  1144. IN HANDLE ProcessID,
  1145. IN PWMI_LOGGER_CONTEXT pLogger,
  1146. IN PRTL_PROCESS_MODULE_INFORMATION pModuleInfo,
  1147. IN PSYSTEM_THREAD_INFORMATION pThreadInfo
  1148. )
  1149. {
  1150. UNICODE_STRING wstrModuleName;
  1151. ANSI_STRING astrModuleName;
  1152. ULONG sizeModuleName;
  1153. ULONG sizeBuffer;
  1154. PCHAR pAuxInfo;
  1155. PWMI_IMAGELOAD_INFORMATION ImageLoadInfo;
  1156. if ((pLogger == NULL) || (pModuleInfo == NULL) || (pThreadInfo == NULL))
  1157. return;
  1158. RtlInitAnsiString( & astrModuleName, pModuleInfo->FullPathName);
  1159. sizeModuleName = sizeof(WCHAR) * (astrModuleName.Length);
  1160. sizeBuffer = sizeModuleName + sizeof(WCHAR)
  1161. + FIELD_OFFSET (WMI_IMAGELOAD_INFORMATION, FileName);
  1162. ImageLoadInfo = (PWMI_IMAGELOAD_INFORMATION)
  1163. WmipGetTraceBuffer(
  1164. pLogger,
  1165. pThreadInfo,
  1166. EVENT_TRACE_GROUP_PROCESS + EVENT_TRACE_TYPE_LOAD,
  1167. sizeBuffer);
  1168. if (ImageLoadInfo == NULL) {
  1169. return;
  1170. }
  1171. ImageLoadInfo->ImageBase = pModuleInfo->ImageBase;
  1172. ImageLoadInfo->ImageSize = pModuleInfo->ImageSize;
  1173. ImageLoadInfo->ProcessId = HandleToUlong(ProcessID);
  1174. wstrModuleName.Buffer = (LPWSTR) &ImageLoadInfo->FileName[0];
  1175. wstrModuleName.MaximumLength = (USHORT) sizeModuleName + sizeof(WCHAR);
  1176. RtlAnsiStringToUnicodeString(& wstrModuleName, & astrModuleName, FALSE);
  1177. }
  1178. ULONG
  1179. WmipSysModuleRunDown(
  1180. IN PWMI_LOGGER_CONTEXT pLogger,
  1181. IN PSYSTEM_THREAD_INFORMATION pThreadInfo
  1182. )
  1183. {
  1184. NTSTATUS status = STATUS_SUCCESS;
  1185. char * pLargeBuffer1;
  1186. ULONG ReturnLength;
  1187. ULONG CurrentBufferSize;
  1188. ULONG i;
  1189. PRTL_PROCESS_MODULES pModules;
  1190. PRTL_PROCESS_MODULE_INFORMATION pModuleInfo;
  1191. pLargeBuffer1 = WmipMemReserve(MAX_BUFFER_SIZE);
  1192. if (pLargeBuffer1 == NULL)
  1193. {
  1194. status = STATUS_NO_MEMORY;
  1195. goto Cleanup;
  1196. }
  1197. if (WmipMemCommit(pLargeBuffer1, BUFFER_SIZE) == NULL)
  1198. {
  1199. status = STATUS_NO_MEMORY;
  1200. goto Cleanup;
  1201. }
  1202. CurrentBufferSize = BUFFER_SIZE;
  1203. retry:
  1204. status = NtQuerySystemInformation(
  1205. SystemModuleInformation,
  1206. pLargeBuffer1,
  1207. CurrentBufferSize,
  1208. &ReturnLength);
  1209. if (status == STATUS_INFO_LENGTH_MISMATCH)
  1210. {
  1211. // Increase buffer size.
  1212. //
  1213. CurrentBufferSize += 8192;
  1214. if (WmipMemCommit(pLargeBuffer1, CurrentBufferSize) == NULL)
  1215. {
  1216. status = STATUS_NO_MEMORY;
  1217. goto Cleanup;
  1218. }
  1219. goto retry;
  1220. }
  1221. if (!NT_SUCCESS(status))
  1222. {
  1223. goto Cleanup;
  1224. }
  1225. pModules = (PRTL_PROCESS_MODULES) pLargeBuffer1;
  1226. for (i = 0, pModuleInfo = & (pModules->Modules[0]);
  1227. i < pModules->NumberOfModules;
  1228. i ++, pModuleInfo ++)
  1229. {
  1230. WmipLogImageLoadEvent(NULL, pLogger, pModuleInfo, pThreadInfo);
  1231. }
  1232. Cleanup:
  1233. if (pLargeBuffer1)
  1234. {
  1235. WmipMemFree(pLargeBuffer1);
  1236. }
  1237. return WmipSetDosError(WmipNtStatusToDosError(status));
  1238. }
  1239. ULONG
  1240. WmipProcessModuleRunDown(
  1241. IN PWMI_LOGGER_CONTEXT pLogger,
  1242. IN HANDLE ProcessID,
  1243. IN PSYSTEM_THREAD_INFORMATION pThreadInfo)
  1244. {
  1245. NTSTATUS status = STATUS_SUCCESS;
  1246. ULONG i;
  1247. PRTL_DEBUG_INFORMATION pLargeBuffer1 = NULL;
  1248. pLargeBuffer1 = RtlCreateQueryDebugBuffer(0, FALSE);
  1249. if (pLargeBuffer1 == NULL)
  1250. {
  1251. status = STATUS_NO_MEMORY;
  1252. goto Cleanup;
  1253. }
  1254. status = RtlQueryProcessDebugInformation(
  1255. ProcessID,
  1256. RTL_QUERY_PROCESS_NONINVASIVE | RTL_QUERY_PROCESS_MODULES,
  1257. pLargeBuffer1);
  1258. if ( !NT_SUCCESS(status) || (pLargeBuffer1->Modules == NULL) )
  1259. {
  1260. goto Cleanup;
  1261. }
  1262. for (i = 0; i < pLargeBuffer1->Modules->NumberOfModules; i ++)
  1263. {
  1264. WmipLogImageLoadEvent(
  1265. ProcessID,
  1266. pLogger,
  1267. & (pLargeBuffer1->Modules->Modules[i]),
  1268. pThreadInfo);
  1269. }
  1270. Cleanup:
  1271. if (pLargeBuffer1)
  1272. {
  1273. RtlDestroyQueryDebugBuffer(pLargeBuffer1);
  1274. }
  1275. return WmipSetDosError(WmipNtStatusToDosError(status));
  1276. }
  1277. NTSTATUS
  1278. WmipProcessRunDown(
  1279. IN PWMI_LOGGER_CONTEXT Logger,
  1280. IN ULONG StartFlag,
  1281. IN ULONG fEnableFlags
  1282. )
  1283. {
  1284. PSYSTEM_PROCESS_INFORMATION pProcessInfo;
  1285. PSYSTEM_THREAD_INFORMATION pThreadInfo;
  1286. char* LargeBuffer1;
  1287. NTSTATUS status;
  1288. ULONG ReturnLength;
  1289. ULONG CurrentBufferSize;
  1290. ULONG GroupType;
  1291. ULONG TotalOffset = 0;
  1292. OBJECT_ATTRIBUTES objectAttributes;
  1293. BOOLEAN WasEnabled = TRUE;
  1294. BOOLEAN bExtended = TRUE;
  1295. LargeBuffer1 = WmipMemReserve ( MAX_BUFFER_SIZE );
  1296. if (LargeBuffer1 == NULL) {
  1297. return STATUS_NO_MEMORY;
  1298. }
  1299. if (WmipMemCommit (LargeBuffer1, BUFFER_SIZE) == NULL) {
  1300. return STATUS_NO_MEMORY;
  1301. }
  1302. CurrentBufferSize = BUFFER_SIZE;
  1303. retry:
  1304. if (bExtended) {
  1305. status = NtQuerySystemInformation(
  1306. SystemExtendedProcessInformation,
  1307. LargeBuffer1,
  1308. CurrentBufferSize,
  1309. &ReturnLength
  1310. );
  1311. }
  1312. else {
  1313. status = NtQuerySystemInformation(
  1314. SystemProcessInformation,
  1315. LargeBuffer1,
  1316. CurrentBufferSize,
  1317. &ReturnLength
  1318. );
  1319. }
  1320. if (status == STATUS_INFO_LENGTH_MISMATCH) {
  1321. //
  1322. // Increase buffer size.
  1323. //
  1324. CurrentBufferSize += 8192;
  1325. if (WmipMemCommit (LargeBuffer1, CurrentBufferSize) == NULL) {
  1326. return STATUS_NO_MEMORY;
  1327. }
  1328. goto retry;
  1329. }
  1330. if (!NT_SUCCESS(status)) {
  1331. if (bExtended) {
  1332. bExtended = FALSE;
  1333. goto retry;
  1334. }
  1335. WmipMemFree(LargeBuffer1);
  1336. return(status);
  1337. }
  1338. //
  1339. // Adjust Privileges to obtain the module information
  1340. //
  1341. if (fEnableFlags & EVENT_TRACE_FLAG_IMAGE_LOAD) {
  1342. status = RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE,
  1343. TRUE, FALSE, &WasEnabled);
  1344. if (!NT_SUCCESS(status)) {
  1345. WmipMemFree(LargeBuffer1);
  1346. return (status);
  1347. }
  1348. }
  1349. TotalOffset = 0;
  1350. pProcessInfo = (SYSTEM_PROCESS_INFORMATION *) LargeBuffer1;
  1351. while (TRUE) {
  1352. ULONG Size;
  1353. ULONG Length = 0;
  1354. ULONG SidLength = 0;
  1355. PUCHAR AuxPtr;
  1356. PULONG_PTR AuxInfo;
  1357. ANSI_STRING s;
  1358. HANDLE Token;
  1359. HANDLE pProcess;
  1360. PCLIENT_ID Cid;
  1361. ULONG TempInfo[128];
  1362. PWMI_PROCESS_INFORMATION WmiProcessInfo;
  1363. Size = FIELD_OFFSET(WMI_PROCESS_INFORMATION, Sid);
  1364. GroupType = EVENT_TRACE_GROUP_PROCESS +
  1365. ((StartFlag) ? EVENT_TRACE_TYPE_DC_START
  1366. : EVENT_TRACE_TYPE_DC_END);
  1367. pThreadInfo = (PSYSTEM_THREAD_INFORMATION) (pProcessInfo+1);
  1368. if (pProcessInfo->NumberOfThreads > 0) {
  1369. Cid = (PCLIENT_ID) &pThreadInfo->ClientId;
  1370. }
  1371. else {
  1372. Cid = NULL;
  1373. }
  1374. // if at termination, rundown thread first before process
  1375. if ( (!StartFlag) &&
  1376. (fEnableFlags & EVENT_TRACE_FLAG_THREAD) ){
  1377. status = WmipThreadRunDown(Logger,
  1378. pProcessInfo,
  1379. StartFlag,
  1380. bExtended);
  1381. if (!NT_SUCCESS(status)) {
  1382. break;
  1383. }
  1384. }
  1385. if (fEnableFlags & EVENT_TRACE_FLAG_PROCESS) {
  1386. if ( pProcessInfo->ImageName.Buffer &&
  1387. pProcessInfo->ImageName.Length > 0 ) {
  1388. RtlUnicodeStringToAnsiString(
  1389. &s,
  1390. (PUNICODE_STRING)&pProcessInfo->ImageName,
  1391. TRUE);
  1392. Length = s.Length + 1;
  1393. }
  1394. else {
  1395. Length = 1;
  1396. }
  1397. InitializeObjectAttributes(
  1398. &objectAttributes, 0, 0, NULL, NULL);
  1399. status = NtOpenProcess(
  1400. &pProcess,
  1401. PROCESS_QUERY_INFORMATION,
  1402. &objectAttributes,
  1403. Cid);
  1404. if (NT_SUCCESS(status)) {
  1405. status = NtOpenProcessToken(
  1406. pProcess,
  1407. TOKEN_READ,
  1408. &Token);
  1409. if (NT_SUCCESS(status)) {
  1410. status = NtQueryInformationToken(
  1411. Token,
  1412. TokenUser,
  1413. TempInfo,
  1414. 256,
  1415. &SidLength);
  1416. NtClose(Token);
  1417. }
  1418. NtClose(pProcess);
  1419. }
  1420. if ( (!NT_SUCCESS(status)) || SidLength <= 0) {
  1421. TempInfo[0] = 0;
  1422. SidLength = sizeof(ULONG);
  1423. }
  1424. Size += Length + SidLength;
  1425. WmiProcessInfo = (PWMI_PROCESS_INFORMATION)
  1426. WmipGetTraceBuffer( Logger,
  1427. pThreadInfo,
  1428. GroupType,
  1429. Size);
  1430. if (WmiProcessInfo == NULL) {
  1431. status = STATUS_NO_MEMORY;
  1432. break;
  1433. }
  1434. WmiProcessInfo->ProcessId = HandleToUlong(pProcessInfo->UniqueProcessId);
  1435. WmiProcessInfo->ParentId = HandleToUlong(pProcessInfo->InheritedFromUniqueProcessId);
  1436. WmiProcessInfo->SessionId = pProcessInfo->SessionId;
  1437. WmiProcessInfo->PageDirectoryBase = pProcessInfo->PageDirectoryBase;
  1438. WmiProcessInfo->ExitStatus = 0;
  1439. AuxPtr = (PUCHAR) (&WmiProcessInfo->Sid);
  1440. RtlCopyMemory(AuxPtr, &TempInfo, SidLength);
  1441. AuxPtr += SidLength;
  1442. if ( Length > 1) {
  1443. RtlCopyMemory(AuxPtr, s.Buffer, Length);
  1444. AuxPtr += Length;
  1445. RtlFreeAnsiString(&s);
  1446. }
  1447. *AuxPtr = '\0';
  1448. AuxPtr++;
  1449. }
  1450. // if at beginning, trace threads after process
  1451. if (StartFlag) {
  1452. if (fEnableFlags & EVENT_TRACE_FLAG_THREAD) {
  1453. WmipThreadRunDown(Logger, pProcessInfo, StartFlag, bExtended);
  1454. }
  1455. if (fEnableFlags & EVENT_TRACE_FLAG_IMAGE_LOAD) {
  1456. if (pProcessInfo->UniqueProcessId == 0) {
  1457. WmipSysModuleRunDown(Logger, pThreadInfo);
  1458. }
  1459. else
  1460. WmipProcessModuleRunDown(
  1461. Logger,
  1462. (HANDLE) pProcessInfo->UniqueProcessId,
  1463. pThreadInfo);
  1464. }
  1465. }
  1466. if (pProcessInfo->NextEntryOffset == 0) {
  1467. break;
  1468. }
  1469. TotalOffset += pProcessInfo->NextEntryOffset;
  1470. pProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&LargeBuffer1[TotalOffset];
  1471. }
  1472. //
  1473. // Restore privileges back to what it was before
  1474. //
  1475. if (fEnableFlags & EVENT_TRACE_FLAG_IMAGE_LOAD) {
  1476. status = RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE,
  1477. WasEnabled,
  1478. FALSE,
  1479. &WasEnabled);
  1480. }
  1481. WmipMemFree(LargeBuffer1);
  1482. return status;
  1483. }
  1484. VOID
  1485. WmipInitString(
  1486. IN PVOID Destination,
  1487. IN PVOID Buffer,
  1488. IN ULONG Size
  1489. )
  1490. {
  1491. PSTRING s = (PSTRING) Destination;
  1492. s->Buffer = Buffer;
  1493. s->Length = 0;
  1494. if (Buffer != NULL)
  1495. s->MaximumLength = (USHORT) Size;
  1496. else
  1497. s->MaximumLength = 0;
  1498. }
  1499. VOID
  1500. WmipGenericTraceEnable(
  1501. IN ULONG RequestCode,
  1502. IN PVOID Buffer,
  1503. IN OUT PVOID *RequestAddress
  1504. )
  1505. {
  1506. PGUIDMAPENTRY pControlGMEntry = *RequestAddress;
  1507. PWNODE_HEADER Wnode = (PWNODE_HEADER) Buffer;
  1508. PTRACE_REG_INFO pTraceRegInfo;
  1509. PTRACE_ENABLE_CONTEXT pContext = (PTRACE_ENABLE_CONTEXT)&Wnode->HistoricalContext;
  1510. *RequestAddress = NULL;
  1511. if (Wnode == NULL || pControlGMEntry == NULL)
  1512. return;
  1513. if (!Wnode->Flags & WNODE_FLAG_TRACED_GUID)
  1514. return;
  1515. pTraceRegInfo = pControlGMEntry->pControlGuidData;
  1516. WmipAssert(pTraceRegInfo != NULL);
  1517. if (pTraceRegInfo->InProgressEvent != NULL) {
  1518. LARGE_INTEGER Timeout = {(ULONG)(-NOTIFY_RETRY_COUNT * 1000 * 10), -1};
  1519. // TODO: Raghu - what if it times out??
  1520. NtWaitForSingleObject(pTraceRegInfo->InProgressEvent, 0, &Timeout);
  1521. }
  1522. *RequestAddress = pTraceRegInfo->NotifyRoutine;
  1523. if (RequestCode == WMI_ENABLE_EVENTS) {
  1524. pControlGMEntry->LoggerContext = Wnode->HistoricalContext;
  1525. if (pContext->InternalFlag & EVENT_TRACE_INTERNAL_FLAG_PRIVATE) {
  1526. pTraceRegInfo->EnabledState = TRUE;
  1527. if (!WmipIsPrivateLoggerOn())
  1528. *RequestAddress = NULL; // Do not notify if the logger is not up.
  1529. }
  1530. }
  1531. else if (RequestCode == WMI_DISABLE_EVENTS) {
  1532. if (pContext->InternalFlag & EVENT_TRACE_INTERNAL_FLAG_PRIVATE) {
  1533. pTraceRegInfo->EnabledState = FALSE;
  1534. }
  1535. pControlGMEntry->LoggerContext = 0;
  1536. }
  1537. }
  1538. ULONG
  1539. WmipRelogHeaderToLogFile(
  1540. IN OUT PWMI_LOGGER_INFORMATION LoggerInfo,
  1541. IN PSYSTEM_TRACE_HEADER RelogProp
  1542. )
  1543. {
  1544. PTRACE_LOGFILE_HEADER RelogFileHeader;
  1545. LPWSTR FileName = NULL;
  1546. ULONG RelogPropSize;
  1547. HANDLE LogFile = INVALID_HANDLE_VALUE;
  1548. ULONG BufferSize;
  1549. IO_STATUS_BLOCK IoStatus;
  1550. PWMI_BUFFER_HEADER Buffer;
  1551. LPWSTR FileNameBuffer = NULL;
  1552. PUCHAR BufferSpace;
  1553. NTSTATUS Status;
  1554. RelogFileHeader = (PTRACE_LOGFILE_HEADER) ((PUCHAR)RelogProp +
  1555. sizeof(SYSTEM_TRACE_HEADER) );
  1556. RelogPropSize = RelogProp->Packet.Size;
  1557. FileName = (LPWSTR) LoggerInfo->LogFileName.Buffer;
  1558. if (FileName == NULL) {
  1559. return WmipSetDosError(ERROR_BAD_PATHNAME);
  1560. }
  1561. LogFile = WmipCreateFile(
  1562. FileName,
  1563. FILE_GENERIC_WRITE,
  1564. FILE_SHARE_READ,
  1565. FILE_OVERWRITE_IF,
  1566. 0);
  1567. if (LogFile == INVALID_HANDLE_VALUE) {
  1568. return WmipSetDosError(ERROR_BAD_PATHNAME);
  1569. }
  1570. LoggerInfo->LogFileHandle = LogFile;
  1571. LoggerInfo->Wnode.ClientContext = RelogFileHeader->ReservedFlags;
  1572. LoggerInfo->NumberOfProcessors = RelogFileHeader->NumberOfProcessors;
  1573. BufferSize = LoggerInfo->BufferSize * 1024;
  1574. BufferSpace = WmipAlloc(BufferSize);
  1575. if (BufferSpace == NULL) {
  1576. NtClose(LogFile);
  1577. return WmipSetDosError(ERROR_NOT_ENOUGH_MEMORY);
  1578. }
  1579. // initialize buffer first
  1580. RtlZeroMemory(BufferSpace, BufferSize);
  1581. Buffer = (PWMI_BUFFER_HEADER) BufferSpace;
  1582. Buffer->Offset = sizeof(WMI_BUFFER_HEADER);
  1583. //
  1584. // We are making this an Application Trace always.
  1585. // However, if two application traces are relogged
  1586. // the Guidmaps are not really consolidated.
  1587. //
  1588. Buffer->Wnode.Guid = LoggerInfo->Wnode.Guid;
  1589. RelogFileHeader->LogFileMode = EVENT_TRACE_RELOG_MODE;
  1590. Buffer->Wnode.BufferSize = BufferSize;
  1591. Buffer->ClientContext.Alignment = (UCHAR)WmiTraceAlignment;
  1592. Buffer->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
  1593. RelogFileHeader->BuffersWritten = 1;
  1594. LoggerInfo->BuffersWritten = 1;
  1595. Buffer->Offset = sizeof(WMI_BUFFER_HEADER) + RelogPropSize;
  1596. //
  1597. // Copy the Old LogFileHeader
  1598. //
  1599. RtlCopyMemory((char*) Buffer + sizeof(WMI_BUFFER_HEADER),
  1600. RelogProp,
  1601. RelogPropSize
  1602. );
  1603. if (Buffer->Offset < BufferSize) {
  1604. RtlFillMemory(
  1605. (char *) Buffer + Buffer->Offset,
  1606. BufferSize - Buffer->Offset,
  1607. 0xFF);
  1608. }
  1609. Status = NtWriteFile(
  1610. LogFile,
  1611. NULL,
  1612. NULL,
  1613. NULL,
  1614. &IoStatus,
  1615. BufferSpace,
  1616. BufferSize,
  1617. NULL,
  1618. NULL);
  1619. NtClose(LogFile);
  1620. LogFile = CreateFileW(
  1621. FileName,
  1622. GENERIC_WRITE,
  1623. FILE_SHARE_READ,
  1624. NULL,
  1625. OPEN_EXISTING,
  1626. FILE_FLAG_NO_BUFFERING,
  1627. NULL
  1628. );
  1629. WmipFree(BufferSpace);
  1630. if (LogFile == INVALID_HANDLE_VALUE) {
  1631. return GetLastError();
  1632. }
  1633. LoggerInfo->LogFileHandle = LogFile;
  1634. return ERROR_SUCCESS;
  1635. }
  1636. ULONG
  1637. WmipAddLogHeaderToLogFile(
  1638. IN OUT PWMI_LOGGER_INFORMATION LoggerInfo,
  1639. IN PWMI_REF_CLOCK RefClock,
  1640. IN ULONG Update
  1641. )
  1642. {
  1643. NTSTATUS Status;
  1644. HANDLE LogFile = INVALID_HANDLE_VALUE;
  1645. ULONG BufferSize;
  1646. ULONG MemorySize;
  1647. ULONG TraceKernel;
  1648. SYSTEM_BASIC_INFORMATION SystemInfo;
  1649. WMI_LOGGER_CONTEXT Logger;
  1650. IO_STATUS_BLOCK IoStatus;
  1651. PWMI_BUFFER_HEADER Buffer;
  1652. FILE_POSITION_INFORMATION FileInfo;
  1653. LPWSTR FileName = NULL;
  1654. LPWSTR FileNameBuffer = NULL;
  1655. ULONG HeaderSize;
  1656. struct WMI_LOGFILE_HEADER {
  1657. WMI_BUFFER_HEADER BufferHeader;
  1658. SYSTEM_TRACE_HEADER SystemHeader;
  1659. TRACE_LOGFILE_HEADER LogFileHeader;
  1660. };
  1661. struct WMI_LOGFILE_HEADER LoggerBuffer;
  1662. BOOLEAN bLogFileAppend =
  1663. (LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_APPEND)
  1664. ? (TRUE) : (FALSE);
  1665. if (LoggerInfo == NULL)
  1666. return WmipSetDosError(ERROR_INVALID_PARAMETER);
  1667. if (LoggerInfo->Wnode.BufferSize < sizeof(WMI_LOGGER_INFORMATION))
  1668. return WmipSetDosError(ERROR_INVALID_PARAMETER);
  1669. if ( !(LoggerInfo->Wnode.Flags & WNODE_FLAG_TRACED_GUID) )
  1670. return WmipSetDosError(ERROR_INVALID_PARAMETER);
  1671. if ((LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_NEWFILE) &&
  1672. (LoggerInfo->LogFileName.Length > 0)) {
  1673. FileName = (LPWSTR) WmipAlloc(LoggerInfo->LogFileName.Length + 64);
  1674. if (FileName == NULL) {
  1675. return WmipSetDosError(ERROR_NOT_ENOUGH_MEMORY);
  1676. }
  1677. swprintf(FileName, LoggerInfo->LogFileName.Buffer, 1);
  1678. FileNameBuffer = FileName;
  1679. }
  1680. if (FileName == NULL)
  1681. FileName = (LPWSTR) LoggerInfo->LogFileName.Buffer;
  1682. //
  1683. // If it is Append Mode, we need to open the file and make sure the
  1684. // pick up the BufferSize
  1685. //
  1686. if ( bLogFileAppend ) {
  1687. FILE_STANDARD_INFORMATION FileStdInfo;
  1688. ULONG ReadSize = sizeof(WMI_BUFFER_HEADER)
  1689. + sizeof(SYSTEM_TRACE_HEADER)
  1690. + sizeof(TRACE_LOGFILE_HEADER);
  1691. ULONG nBytesRead = 0;
  1692. //
  1693. // Update and Append do not mix. To Append LoggerInfo
  1694. // must have LogFileName
  1695. //
  1696. if ( (Update) || (LoggerInfo->LogFileName.Length <= 0) ) {
  1697. if (FileNameBuffer != NULL) {
  1698. WmipFree(FileNameBuffer);
  1699. }
  1700. return WmipSetDosError(ERROR_INVALID_PARAMETER);
  1701. }
  1702. LogFile = CreateFileW(FileName,
  1703. GENERIC_READ | GENERIC_WRITE,
  1704. FILE_SHARE_READ,
  1705. NULL,
  1706. OPEN_EXISTING,
  1707. FILE_ATTRIBUTE_NORMAL,
  1708. NULL);
  1709. if (LogFile == INVALID_HANDLE_VALUE) {
  1710. // cannot OPEN_EXISTING, assume that logfile is not there and
  1711. // create a new one.
  1712. //
  1713. bLogFileAppend = FALSE;
  1714. LoggerInfo->LogFileMode = LoggerInfo->LogFileMode
  1715. & (~ (EVENT_TRACE_FILE_MODE_APPEND));
  1716. }
  1717. else {
  1718. // read TRACE_LOGFILE_HEADER structure and update LoggerInfo
  1719. // members.
  1720. //
  1721. Status = ReadFile(LogFile,
  1722. (LPVOID) & LoggerBuffer,
  1723. ReadSize,
  1724. & nBytesRead,
  1725. NULL);
  1726. if (nBytesRead < ReadSize) {
  1727. NtClose(LogFile);
  1728. if (FileNameBuffer != NULL) {
  1729. WmipFree(FileNameBuffer);
  1730. }
  1731. return WmipSetDosError(ERROR_BAD_PATHNAME);
  1732. }
  1733. if ( LoggerBuffer.LogFileHeader.LogFileMode
  1734. & EVENT_TRACE_FILE_MODE_CIRCULAR) {
  1735. NtClose(LogFile);
  1736. if (FileNameBuffer != NULL) {
  1737. WmipFree(FileNameBuffer);
  1738. }
  1739. return WmipSetDosError(ERROR_BAD_PATHNAME);
  1740. }
  1741. LoggerInfo->BufferSize =
  1742. LoggerBuffer.LogFileHeader.BufferSize / 1024;
  1743. //
  1744. // If it's append, the GuidMap buffers are not accounted for
  1745. // in the BuffersWritten count. The starttrace call will fail
  1746. // on checksum error if it is not adjusted properly. However,
  1747. // this will trash the GuidMap entries in this file.
  1748. //
  1749. Status = NtQueryInformationFile(
  1750. LogFile,
  1751. &IoStatus,
  1752. &FileStdInfo,
  1753. sizeof(FILE_STANDARD_INFORMATION),
  1754. FileStandardInformation
  1755. );
  1756. if (NT_SUCCESS(Status) ) {
  1757. ULONG64 FileSize = FileStdInfo.AllocationSize.QuadPart;
  1758. ULONG64 BuffersWritten = FileSize / (ULONG64) LoggerBuffer.LogFileHeader.BufferSize;
  1759. LoggerInfo->BuffersWritten = (ULONG)BuffersWritten;
  1760. LoggerBuffer.LogFileHeader.BuffersWritten = (ULONG)BuffersWritten;
  1761. }
  1762. else {
  1763. NtClose(LogFile);
  1764. if (FileNameBuffer != NULL) {
  1765. WmipFree(FileNameBuffer);
  1766. }
  1767. return WmipNtStatusToDosError(Status);
  1768. }
  1769. LoggerInfo->MaximumFileSize =
  1770. LoggerBuffer.LogFileHeader.MaximumFileSize;
  1771. // Write back logfile append mode so WmipFinalizeLogFile() correctly
  1772. // update BuffersWritten field
  1773. //
  1774. FileInfo.CurrentByteOffset.QuadPart =
  1775. LOGFILE_FIELD_OFFSET(EndTime);
  1776. Status = NtSetInformationFile(LogFile,
  1777. & IoStatus,
  1778. & FileInfo,
  1779. sizeof(FILE_POSITION_INFORMATION),
  1780. FilePositionInformation);
  1781. if (!NT_SUCCESS(Status)) {
  1782. NtClose(LogFile);
  1783. if (FileNameBuffer != NULL) {
  1784. WmipFree(FileNameBuffer);
  1785. }
  1786. return WmipSetDosError(WmipNtStatusToDosError(Status));
  1787. }
  1788. LoggerBuffer.LogFileHeader.EndTime.QuadPart = 0;
  1789. Status = NtWriteFile(LogFile,
  1790. NULL,
  1791. NULL,
  1792. NULL,
  1793. & IoStatus,
  1794. & LoggerBuffer.LogFileHeader.EndTime,
  1795. sizeof(LARGE_INTEGER),
  1796. NULL,
  1797. NULL);
  1798. if (! NT_SUCCESS(Status)) {
  1799. NtClose(LogFile);
  1800. if (FileNameBuffer != NULL) {
  1801. WmipFree(FileNameBuffer);
  1802. }
  1803. return WmipSetDosError(WmipNtStatusToDosError(Status));
  1804. }
  1805. // build checksum structure
  1806. //
  1807. if (LoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) {
  1808. LoggerInfo->Checksum = NULL;
  1809. }
  1810. else {
  1811. LoggerInfo->Checksum = WmipAlloc(
  1812. sizeof(WNODE_HEADER) + sizeof(TRACE_LOGFILE_HEADER));
  1813. if (LoggerInfo->Checksum != NULL) {
  1814. PBYTE ptrChecksum = LoggerInfo->Checksum;
  1815. RtlCopyMemory(ptrChecksum,
  1816. & LoggerBuffer.BufferHeader,
  1817. sizeof(WNODE_HEADER));
  1818. ptrChecksum += sizeof(WNODE_HEADER);
  1819. RtlCopyMemory(ptrChecksum,
  1820. & LoggerBuffer.LogFileHeader,
  1821. sizeof(TRACE_LOGFILE_HEADER));
  1822. }
  1823. else {
  1824. if (FileNameBuffer != NULL) {
  1825. WmipFree(FileNameBuffer);
  1826. }
  1827. return WmipSetDosError(ERROR_NOT_ENOUGH_MEMORY);
  1828. }
  1829. }
  1830. }
  1831. }
  1832. // get the system parameters first
  1833. LoggerInfo->LogFileHandle = NULL;
  1834. Status = NtQuerySystemInformation(
  1835. SystemBasicInformation,
  1836. &SystemInfo, sizeof (SystemInfo), NULL);
  1837. if (!NT_SUCCESS(Status)) {
  1838. if (FileNameBuffer != NULL) {
  1839. WmipFree(FileNameBuffer);
  1840. }
  1841. return WmipSetDosError(WmipNtStatusToDosError(Status));
  1842. }
  1843. // choose some logical default value for buffer size if user
  1844. // has not provided one
  1845. MemorySize = SystemInfo.NumberOfPhysicalPages * SystemInfo.PageSize
  1846. / 1024 / 1024;
  1847. if (MemorySize <= 32)
  1848. BufferSize = SystemInfo.PageSize;
  1849. else if (MemorySize <= 64)
  1850. BufferSize = SystemInfo.PageSize;
  1851. else if (MemorySize <= 128)
  1852. BufferSize = SystemInfo.PageSize * 2;
  1853. else if (MemorySize <= 256)
  1854. BufferSize = SystemInfo.PageSize * 2;
  1855. else if (MemorySize > 512)
  1856. BufferSize = SystemInfo.PageSize * 2;
  1857. else if (MemorySize <= 256)
  1858. BufferSize = SystemInfo.PageSize * 2;
  1859. else if (MemorySize > 512)
  1860. BufferSize = 64 * 1024; // allocation size
  1861. else // > 256 && < 512
  1862. BufferSize = SystemInfo.PageSize * 2;
  1863. if (LoggerInfo->BufferSize > 1024) // limit to 1Mb
  1864. BufferSize = 1024 * 1024;
  1865. else if (LoggerInfo->BufferSize > 0)
  1866. BufferSize = LoggerInfo->BufferSize * 1024;
  1867. TraceKernel = IsEqualGUID(&LoggerInfo->Wnode.Guid, &SystemTraceControlGuid);
  1868. if (!TraceKernel) {
  1869. GUID guid;
  1870. RtlZeroMemory(&guid, sizeof(GUID));
  1871. if (IsEqualGUID(&LoggerInfo->Wnode.Guid, &guid)) {
  1872. // Generate a Guid for this logger stream
  1873. // This will ensure buffer filtering at the WMI service
  1874. // based on this GUID.
  1875. UUID uid;
  1876. UuidCreate(&uid);
  1877. LoggerInfo->Wnode.Guid = uid;
  1878. }
  1879. }
  1880. if (!Update) {
  1881. // don't want to update BufferSize information if the request is
  1882. // to update logger session
  1883. //
  1884. LoggerInfo->BufferSize = BufferSize / 1024;
  1885. }
  1886. if (LoggerInfo->LogFileName.Length <= 0)
  1887. return ERROR_SUCCESS; //goto SendToKm;
  1888. //
  1889. // We assumed the exposed API has checked for either RealTime or FileName
  1890. // is provided
  1891. //
  1892. // open the file for writing synchronously for the logger
  1893. // others may want to read it as well.
  1894. // For logfile append mode, logfile has been opened previously
  1895. //
  1896. if (! bLogFileAppend) {
  1897. /* LogFile = CreateFileW(
  1898. (PWCHAR) LoggerInfo->LogFileName.Buffer,
  1899. GENERIC_WRITE,
  1900. FILE_SHARE_READ,
  1901. NULL,
  1902. CREATE_ALWAYS,
  1903. FILE_ATTRIBUTE_NORMAL,
  1904. NULL
  1905. ); */
  1906. LogFile = WmipCreateFile(
  1907. FileName,
  1908. FILE_GENERIC_WRITE,
  1909. FILE_SHARE_READ,
  1910. FILE_OVERWRITE_IF,
  1911. 0);
  1912. if (LogFile == INVALID_HANDLE_VALUE) {
  1913. if (FileNameBuffer != NULL) {
  1914. WmipFree(FileNameBuffer);
  1915. }
  1916. return WmipSetDosError(ERROR_BAD_PATHNAME);
  1917. }
  1918. }
  1919. LoggerInfo->LogFileHandle = LogFile;
  1920. //
  1921. // If this is an Update call, then we need to pick up the original
  1922. // buffer size for the LogFileHeader.
  1923. //
  1924. if (Update) {
  1925. PWMI_LOGGER_INFORMATION pTempLoggerInfo;
  1926. PWCHAR strLoggerName = NULL;
  1927. PWCHAR strLogFileName = NULL;
  1928. ULONG ErrCode;
  1929. ULONG SizeNeeded = sizeof(WMI_LOGGER_INFORMATION) + MAXSTR * sizeof(WCHAR) * 2;
  1930. SizeNeeded = (SizeNeeded +7) & ~7;
  1931. pTempLoggerInfo = WmipAlloc(SizeNeeded);
  1932. if (pTempLoggerInfo == NULL) {
  1933. return WmipSetDosError(ERROR_NOT_ENOUGH_MEMORY);
  1934. }
  1935. RtlZeroMemory(pTempLoggerInfo, SizeNeeded);
  1936. pTempLoggerInfo->Wnode.BufferSize = SizeNeeded;
  1937. pTempLoggerInfo->Wnode.Flags |= WNODE_FLAG_TRACED_GUID;
  1938. pTempLoggerInfo->Wnode.HistoricalContext = LoggerInfo->Wnode.HistoricalContext;
  1939. pTempLoggerInfo->Wnode.Guid = LoggerInfo->Wnode.Guid;
  1940. if (LoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) {
  1941. pTempLoggerInfo->LogFileMode |= EVENT_TRACE_PRIVATE_LOGGER_MODE;
  1942. }
  1943. strLoggerName = (PWCHAR) ( ((PUCHAR) pTempLoggerInfo)
  1944. + sizeof(WMI_LOGGER_INFORMATION));
  1945. WmipInitString(&pTempLoggerInfo->LoggerName,
  1946. strLoggerName,
  1947. MAXSTR * sizeof(WCHAR));
  1948. if (LoggerInfo->LoggerName.Length > 0) {
  1949. RtlCopyUnicodeString( &pTempLoggerInfo->LoggerName,
  1950. &LoggerInfo->LoggerName);
  1951. }
  1952. strLogFileName = (PWCHAR) ( ((PUCHAR) pTempLoggerInfo)
  1953. + sizeof(WMI_LOGGER_INFORMATION)
  1954. + MAXSTR * sizeof(WCHAR) );
  1955. WmipInitString(&pTempLoggerInfo->LogFileName,
  1956. strLogFileName,
  1957. MAXSTR * sizeof(WCHAR) );
  1958. //
  1959. // Call QueryLogger
  1960. //
  1961. ErrCode = WmipQueryLogger(pTempLoggerInfo, FALSE);
  1962. BufferSize = pTempLoggerInfo->BufferSize * 1024;
  1963. WmipFree(pTempLoggerInfo);
  1964. if (ErrCode != ERROR_SUCCESS) {
  1965. return ErrCode;
  1966. }
  1967. }
  1968. //
  1969. // Before Allocating the Buffer for Logfile Header make
  1970. // sure the buffer size is atleast as large as the LogFileHeader
  1971. //
  1972. HeaderSize = sizeof(LoggerBuffer)
  1973. + LoggerInfo->LoggerName.Length + sizeof(WCHAR)
  1974. + LoggerInfo->LogFileName.Length + sizeof(WCHAR);
  1975. if (HeaderSize > BufferSize) {
  1976. //
  1977. // Round it to the nearest power of 2 and check for max size 1 MB
  1978. //
  1979. double dTemp = log (HeaderSize / 1024.0) / log (2.0);
  1980. ULONG lTemp = (ULONG) (dTemp + 0.99);
  1981. HeaderSize = (1 << lTemp);
  1982. if (HeaderSize > 1024) {
  1983. NtClose(LogFile);
  1984. if (FileNameBuffer != NULL) {
  1985. WmipFree(FileNameBuffer);
  1986. }
  1987. return WmipSetDosError(ERROR_NOT_ENOUGH_MEMORY);
  1988. }
  1989. LoggerInfo->BufferSize = HeaderSize;
  1990. BufferSize = HeaderSize * 1024;
  1991. }
  1992. // allocate a buffer to write logger header and process/thread
  1993. // rundown information
  1994. //
  1995. Logger.LogFileHandle = LogFile;
  1996. Logger.BufferSize = BufferSize;
  1997. Logger.TimerResolution = SystemInfo.TimerResolution;
  1998. Logger.BufferSpace = WmipAlloc(BufferSize);
  1999. if (Logger.BufferSpace == NULL) {
  2000. NtClose(LogFile);
  2001. if (FileNameBuffer != NULL) {
  2002. WmipFree(FileNameBuffer);
  2003. }
  2004. return WmipSetDosError(ERROR_NOT_ENOUGH_MEMORY);
  2005. }
  2006. Logger.UsePerfClock = LoggerInfo->Wnode.ClientContext;
  2007. // initialize buffer first
  2008. RtlZeroMemory(Logger.BufferSpace, BufferSize);
  2009. Buffer = (PWMI_BUFFER_HEADER) Logger.BufferSpace;
  2010. Buffer->Offset = sizeof(WMI_BUFFER_HEADER);
  2011. if (TraceKernel) {
  2012. Buffer->Wnode.Guid = SystemTraceControlGuid;
  2013. }
  2014. else {
  2015. Buffer->Wnode.Guid = LoggerInfo->Wnode.Guid;
  2016. }
  2017. Buffer->Wnode.BufferSize = BufferSize;
  2018. Buffer->ClientContext.Alignment = (UCHAR)WmiTraceAlignment;
  2019. Buffer->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
  2020. if (bLogFileAppend) {
  2021. Logger.BuffersWritten = LoggerBuffer.LogFileHeader.BuffersWritten;
  2022. SetFilePointer(LogFile, 0, NULL, FILE_END);
  2023. }
  2024. else {
  2025. PTRACE_LOGFILE_HEADER LogfileHeader;
  2026. OSVERSIONINFO sVersionInfo;
  2027. LARGE_INTEGER CurrentTime;
  2028. LARGE_INTEGER Frequency;
  2029. ULONG CpuNum = 0, CpuSpeed;
  2030. Status = NtQueryPerformanceCounter(&CurrentTime, &Frequency);
  2031. Logger.BuffersWritten = 0;
  2032. HeaderSize = sizeof(TRACE_LOGFILE_HEADER)
  2033. + LoggerInfo->LoggerName.Length + sizeof(WCHAR)
  2034. + LoggerInfo->LogFileName.Length + sizeof(WCHAR);
  2035. LogfileHeader = (PTRACE_LOGFILE_HEADER)
  2036. WmipGetTraceBuffer(
  2037. &Logger,
  2038. NULL,
  2039. EVENT_TRACE_GROUP_HEADER + EVENT_TRACE_TYPE_INFO,
  2040. HeaderSize
  2041. );
  2042. if (LogfileHeader == NULL) {
  2043. NtClose(LogFile);
  2044. WmipFree(Logger.BufferSpace);
  2045. if (FileNameBuffer != NULL) {
  2046. WmipFree(FileNameBuffer);
  2047. }
  2048. return WmipSetDosError(ERROR_NOT_ENOUGH_MEMORY);
  2049. }
  2050. LogfileHeader->PerfFreq = Frequency;
  2051. LogfileHeader->ReservedFlags = Logger.UsePerfClock;
  2052. if (NT_SUCCESS(WmipGetCpuSpeed(&CpuNum, &CpuSpeed))) {
  2053. LogfileHeader->CpuSpeedInMHz = CpuSpeed;
  2054. }
  2055. //
  2056. // Start and End Times are wall clock time
  2057. //
  2058. if (RefClock != NULL) {
  2059. PSYSTEM_TRACE_HEADER Header;
  2060. LogfileHeader->StartTime = RefClock->StartTime;
  2061. Header = (PSYSTEM_TRACE_HEADER) ( (char *) LogfileHeader - sizeof(SYSTEM_TRACE_HEADER) );
  2062. Header->SystemTime = RefClock->StartPerfClock;
  2063. }
  2064. else {
  2065. LogfileHeader->StartTime.QuadPart = WmipGetSystemTime();
  2066. }
  2067. RtlZeroMemory(&sVersionInfo, sizeof(OSVERSIONINFO));
  2068. sVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  2069. GetVersionEx(&sVersionInfo);
  2070. LogfileHeader->BufferSize = BufferSize;
  2071. LogfileHeader->VersionDetail.MajorVersion =
  2072. (UCHAR)sVersionInfo.dwMajorVersion;
  2073. LogfileHeader->VersionDetail.MinorVersion =
  2074. (UCHAR)sVersionInfo.dwMinorVersion;
  2075. LogfileHeader->VersionDetail.SubVersion = TRACE_VERSION_MAJOR;
  2076. LogfileHeader->VersionDetail.SubMinorVersion = TRACE_VERSION_MINOR;
  2077. LogfileHeader->ProviderVersion = sVersionInfo.dwBuildNumber;
  2078. LogfileHeader->StartBuffers = 1;
  2079. LogfileHeader->LogFileMode
  2080. = LoggerInfo->LogFileMode & (~(EVENT_TRACE_REAL_TIME_MODE));
  2081. LogfileHeader->NumberOfProcessors = SystemInfo.NumberOfProcessors;
  2082. if (LoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE)
  2083. {
  2084. LoggerInfo->NumberOfProcessors = SystemInfo.NumberOfProcessors;
  2085. }
  2086. LogfileHeader->MaximumFileSize = LoggerInfo->MaximumFileSize;
  2087. LogfileHeader->TimerResolution = SystemInfo.TimerResolution;
  2088. LogfileHeader->LoggerName = (PWCHAR) ( (PUCHAR) LogfileHeader
  2089. + sizeof(TRACE_LOGFILE_HEADER) );
  2090. LogfileHeader->LogFileName = (PWCHAR) ((PUCHAR)LogfileHeader->LoggerName
  2091. + LoggerInfo->LoggerName.Length
  2092. + sizeof (WCHAR));
  2093. RtlCopyMemory(LogfileHeader->LoggerName,
  2094. LoggerInfo->LoggerName.Buffer,
  2095. LoggerInfo->LoggerName.Length + sizeof(WCHAR));
  2096. RtlCopyMemory(LogfileHeader->LogFileName,
  2097. LoggerInfo->LogFileName.Buffer,
  2098. LoggerInfo->LogFileName.Length + sizeof(WCHAR));
  2099. GetTimeZoneInformation(&LogfileHeader->TimeZone);
  2100. LogfileHeader->PointerSize = sizeof(PVOID);
  2101. if (LoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) {
  2102. LoggerInfo->Checksum = NULL;
  2103. }
  2104. else {
  2105. LoggerInfo->Checksum = WmipAlloc(
  2106. sizeof(WNODE_HEADER)
  2107. + sizeof(TRACE_LOGFILE_HEADER));
  2108. if (LoggerInfo->Checksum != NULL) {
  2109. PBYTE ptrChecksum = LoggerInfo->Checksum;
  2110. RtlCopyMemory(ptrChecksum, Buffer, sizeof(WNODE_HEADER));
  2111. ptrChecksum += sizeof(WNODE_HEADER);
  2112. RtlCopyMemory(
  2113. ptrChecksum, LogfileHeader, sizeof(TRACE_LOGFILE_HEADER));
  2114. }
  2115. else {
  2116. NtClose(LogFile);
  2117. WmipFree(Logger.BufferSpace);
  2118. if (FileNameBuffer != NULL) {
  2119. WmipFree(FileNameBuffer);
  2120. }
  2121. return WmipSetDosError(ERROR_NOT_ENOUGH_MEMORY);
  2122. }
  2123. }
  2124. }
  2125. // Dump the GuidMaps to File at the Start
  2126. //
  2127. if (!Update) {
  2128. if (TraceKernel) {
  2129. ULONG EnableFlags = LoggerInfo->EnableFlags;
  2130. if (EnableFlags & EVENT_TRACE_FLAG_EXTENSION) {
  2131. PTRACE_ENABLE_FLAG_EXTENSION tFlagExt;
  2132. tFlagExt = (PTRACE_ENABLE_FLAG_EXTENSION)
  2133. &LoggerInfo->EnableFlags;
  2134. EnableFlags = *(PULONG)((PCHAR)LoggerInfo + tFlagExt->Offset);
  2135. }
  2136. WmipDumpHardwareConfig(&Logger);
  2137. WmipProcessRunDown( &Logger, TRUE, EnableFlags );
  2138. }
  2139. else {
  2140. WmipDumpGuidMaps(&Logger, NULL, FALSE);
  2141. }
  2142. }
  2143. Buffer = (PWMI_BUFFER_HEADER) Logger.BufferSpace;
  2144. // flush the last buffer
  2145. if ( (Buffer->Offset < Logger.BufferSize) &&
  2146. (Buffer->Offset > sizeof(WMI_BUFFER_HEADER)) )
  2147. {
  2148. RtlFillMemory(
  2149. (char *) Buffer + Buffer->Offset,
  2150. Logger.BufferSize - Buffer->Offset,
  2151. 0xFF);
  2152. Status = NtWriteFile(
  2153. LogFile,
  2154. NULL,
  2155. NULL,
  2156. NULL,
  2157. &IoStatus,
  2158. Logger.BufferSpace,
  2159. BufferSize,
  2160. NULL,
  2161. NULL);
  2162. Logger.BuffersWritten++;
  2163. }
  2164. if ((LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_CIRCULAR) ) {
  2165. //
  2166. // We need to write the number of StartBuffers in the
  2167. // Circular Logfile header to process it properly.
  2168. FileInfo.CurrentByteOffset.QuadPart =
  2169. LOGFILE_FIELD_OFFSET(StartBuffers);
  2170. Status = NtSetInformationFile(
  2171. LogFile,
  2172. &IoStatus,
  2173. &FileInfo,
  2174. sizeof(FILE_POSITION_INFORMATION),
  2175. FilePositionInformation
  2176. );
  2177. if (!NT_SUCCESS(Status)) {
  2178. NtClose(LogFile);
  2179. if (FileNameBuffer != NULL) {
  2180. WmipFree(FileNameBuffer);
  2181. }
  2182. return WmipSetDosError(WmipNtStatusToDosError(Status));
  2183. }
  2184. Status = NtWriteFile(
  2185. LogFile,
  2186. NULL,
  2187. NULL,
  2188. NULL,
  2189. &IoStatus,
  2190. &Logger.BuffersWritten,
  2191. sizeof(ULONG),
  2192. NULL,
  2193. NULL
  2194. );
  2195. if (NT_SUCCESS(Status)) {
  2196. PTRACE_LOGFILE_HEADER pLogFileHeader;
  2197. NtFlushBuffersFile(Logger.LogFileHandle, &IoStatus);
  2198. //
  2199. // update StartBuffers in Checksum
  2200. //
  2201. if ( !(LoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE)) {
  2202. if (LoggerInfo->Checksum == NULL) {
  2203. CloseHandle(LogFile);
  2204. return (ERROR_INVALID_DATA);
  2205. }
  2206. pLogFileHeader = (PTRACE_LOGFILE_HEADER)
  2207. (((PUCHAR) LoggerInfo->Checksum) + sizeof(WNODE_HEADER));
  2208. pLogFileHeader->StartBuffers = Logger.BuffersWritten;
  2209. }
  2210. }
  2211. }
  2212. //
  2213. // As a last thing update the Number of BuffersWritten so far
  2214. // in the header and also update the checksum. This is to prevent
  2215. // Logger failing Update calls under high load.
  2216. //
  2217. FileInfo.CurrentByteOffset.QuadPart =
  2218. LOGFILE_FIELD_OFFSET(BuffersWritten);
  2219. Status = NtSetInformationFile(
  2220. LogFile,
  2221. &IoStatus,
  2222. &FileInfo,
  2223. sizeof(FILE_POSITION_INFORMATION),
  2224. FilePositionInformation
  2225. );
  2226. if (!NT_SUCCESS(Status)) {
  2227. NtClose(LogFile);
  2228. return WmipSetDosError(WmipNtStatusToDosError(Status));
  2229. }
  2230. Status = NtWriteFile(
  2231. LogFile,
  2232. NULL,
  2233. NULL,
  2234. NULL,
  2235. &IoStatus,
  2236. &Logger.BuffersWritten,
  2237. sizeof(ULONG),
  2238. NULL,
  2239. NULL
  2240. );
  2241. if (NT_SUCCESS(Status)) {
  2242. PTRACE_LOGFILE_HEADER pLogFileHeader;
  2243. NtFlushBuffersFile(Logger.LogFileHandle, &IoStatus);
  2244. //
  2245. // update StartBuffers in Checksum
  2246. //
  2247. if ( !(LoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE)) {
  2248. if (LoggerInfo->Checksum == NULL) {
  2249. CloseHandle(LogFile);
  2250. return (ERROR_INVALID_DATA);
  2251. }
  2252. pLogFileHeader = (PTRACE_LOGFILE_HEADER)
  2253. (((PUCHAR) LoggerInfo->Checksum) + sizeof(WNODE_HEADER));
  2254. pLogFileHeader->BuffersWritten = Logger.BuffersWritten;
  2255. }
  2256. }
  2257. // Extend the file size if in PREALLOCATE mode
  2258. if (LoggerInfo->MaximumFileSize &&
  2259. (LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_PREALLOCATE)) {
  2260. IO_STATUS_BLOCK IoStatusBlock;
  2261. FILE_END_OF_FILE_INFORMATION EOFInfo;
  2262. EOFInfo.EndOfFile.QuadPart = ((ULONGLONG)LoggerInfo->MaximumFileSize) * (1024 * 1024);
  2263. Status = NtSetInformationFile(LogFile,
  2264. &IoStatusBlock,
  2265. &EOFInfo,
  2266. sizeof(FILE_END_OF_FILE_INFORMATION),
  2267. FileEndOfFileInformation);
  2268. if (!NT_SUCCESS(Status)) {
  2269. NtClose(LogFile);
  2270. return WmipSetDosError(WmipNtStatusToDosError(Status));
  2271. }
  2272. }
  2273. NtClose(LogFile);
  2274. LogFile = CreateFileW(
  2275. FileName,
  2276. GENERIC_WRITE,
  2277. FILE_SHARE_READ,
  2278. NULL,
  2279. OPEN_EXISTING,
  2280. FILE_FLAG_NO_BUFFERING,
  2281. NULL
  2282. );
  2283. if (FileNameBuffer != NULL) {
  2284. WmipFree(FileNameBuffer);
  2285. }
  2286. WmipFree(Logger.BufferSpace);
  2287. if (LogFile == INVALID_HANDLE_VALUE) {
  2288. return GetLastError();
  2289. }
  2290. LoggerInfo->LogFileHandle = LogFile;
  2291. LoggerInfo->BuffersWritten = Logger.BuffersWritten;
  2292. return ERROR_SUCCESS;
  2293. }
  2294. ULONG
  2295. WmipDumpGuidMaps(
  2296. IN PWMI_LOGGER_CONTEXT Logger,
  2297. IN PLIST_ENTRY GuidMapListHeadPtr,
  2298. IN ULONG RealTimeFlag
  2299. )
  2300. /*++
  2301. Routine Description:
  2302. This routine communicates with the WMI Service and obtains all the
  2303. Trace Guids that are currently registered and those guids that unregistered
  2304. in the middle of a Logging session.
  2305. The GuidMaps are dumped to the logfile or added to the current GuidMapList
  2306. for real time processing.
  2307. Arguments:
  2308. Logger Logger Context.
  2309. RealTimeFlag Flag to denote real time processing.
  2310. Return Value:
  2311. Returns the number of Trace GUIDS obtained from the WMI service.
  2312. --*/
  2313. {
  2314. ULONG Status;
  2315. PTRACEGUIDMAP GuidMapList = NULL;
  2316. ULONG MaxGuidCount;
  2317. ULONG TotalGuidCount;
  2318. ULONG ReturnGuidCount;
  2319. ULONG BusyRetries;
  2320. // Ensure that wmi service is around and willing to send us notifications
  2321. #if 0
  2322. Status = WmipEnableNotifications();
  2323. #else
  2324. Status = ERROR_INVALID_PARAMETER;
  2325. #endif
  2326. if (Status != ERROR_SUCCESS)
  2327. {
  2328. SetLastError(Status);
  2329. return(0);
  2330. }
  2331. MaxGuidCount = 10;
  2332. retry:
  2333. TotalGuidCount = 0;
  2334. ReturnGuidCount = 0;
  2335. GuidMapList = WmipAlloc(MaxGuidCount * sizeof(TRACEGUIDMAP));
  2336. if (GuidMapList == NULL)
  2337. {
  2338. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2339. return (0);
  2340. }
  2341. RtlZeroMemory(GuidMapList, MaxGuidCount * sizeof(TRACEGUIDMAP));
  2342. BusyRetries = 0;
  2343. do
  2344. {
  2345. try
  2346. {
  2347. #if 0
  2348. Status = EnumerateTraceGuidMap(WmipDcCtxHandle,
  2349. MaxGuidCount,
  2350. &TotalGuidCount,
  2351. &ReturnGuidCount,
  2352. GuidMapList);
  2353. #endif
  2354. } except(EXCEPTION_EXECUTE_HANDLER) {
  2355. Status = GetExceptionCode();
  2356. if (Status == STATUS_ACCESS_VIOLATION)
  2357. {
  2358. Status = ERROR_NOACCESS;
  2359. WmipFree(GuidMapList);
  2360. SetLastError(Status);
  2361. return (0);
  2362. }
  2363. }
  2364. if (Status == RPC_S_SERVER_TOO_BUSY)
  2365. {
  2366. WmipDebugPrint(("WMI: EnumerateTraceGuidMap too busy for the %d time\n",
  2367. BusyRetries));
  2368. Sleep(RPC_BUSY_WAIT_TIMER);
  2369. BusyRetries++;
  2370. }
  2371. } while ((Status == RPC_S_SERVER_TOO_BUSY) &&
  2372. (BusyRetries < RPC_BUSY_WAIT_RETRIES));
  2373. //
  2374. // If RPC was successful, then write out these events to logfile.
  2375. //
  2376. if (Status == ERROR_MORE_DATA) {
  2377. MaxGuidCount = TotalGuidCount;
  2378. WmipFree(GuidMapList);
  2379. goto retry;
  2380. }
  2381. else if (Status == ERROR_SUCCESS) {
  2382. ULONG GroupType;
  2383. ULONG i;
  2384. ULONG Size;
  2385. PULONG AuxInfo;
  2386. PTRACEGUIDMAP pTraceGuidMap = GuidMapList;
  2387. GroupType = EVENT_TRACE_GROUP_HEADER + EVENT_TRACE_TYPE_GUIDMAP;
  2388. Size = sizeof(TRACEGUIDMAP);
  2389. for (i=0; i < ReturnGuidCount; i++) {
  2390. if (RealTimeFlag) {
  2391. WmipAddGuidHandleToGuidMapList(GuidMapListHeadPtr, pTraceGuidMap->GuidMapHandle,
  2392. &pTraceGuidMap->Guid);
  2393. }
  2394. else {
  2395. AuxInfo = (PULONG) WmipGetTraceBuffer(
  2396. Logger,
  2397. NULL,
  2398. GroupType,
  2399. Size);
  2400. if (AuxInfo == NULL) {
  2401. WmipFree(GuidMapList);
  2402. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2403. return(0);
  2404. }
  2405. RtlCopyMemory(AuxInfo, pTraceGuidMap, sizeof(TRACEGUIDMAP));
  2406. }
  2407. pTraceGuidMap++;
  2408. }
  2409. }
  2410. WmipFree(GuidMapList);
  2411. WmipSetDosError(Status);
  2412. return(ReturnGuidCount);
  2413. }
  2414. ULONG
  2415. WmiUnregisterGuids(
  2416. IN WMIHANDLE WMIHandle,
  2417. IN LPGUID Guid,
  2418. OUT ULONG64 *LoggerContext
  2419. )
  2420. /*++
  2421. Routine Description:
  2422. This routine informs WMI that a data provider is no longer available
  2423. to receive requests for the guids previously registered. WMI will
  2424. unregister any guids registered with this handle.
  2425. Arguments:
  2426. WMIHandle - Handle returned from WMIRegisterGuids that represents
  2427. the guids whose data is not longer available.
  2428. Guid - Pointer to the control Guid which is unregistering
  2429. LoggerContext - Returned value of the LoggerContext
  2430. Return Value:
  2431. Returns status code
  2432. --*/
  2433. {
  2434. ULONG Status;
  2435. ULONG ReturnSize;
  2436. WMIUNREGGUIDS UnregGuids;
  2437. UnregGuids.RequestHandle.Handle64 = (ULONG64)WMIHandle;
  2438. UnregGuids.Guid = *Guid;
  2439. Status = WmipSendWmiKMRequest(NULL,
  2440. IOCTL_WMI_UNREGISTER_GUIDS,
  2441. &UnregGuids,
  2442. sizeof(WMIUNREGGUIDS),
  2443. &UnregGuids,
  2444. sizeof(WMIUNREGGUIDS),
  2445. &ReturnSize,
  2446. NULL);
  2447. if (Status == ERROR_SUCCESS)
  2448. {
  2449. Status = WmipRemoveFromGNList(Guid,
  2450. (PVOID) WMIHandle);
  2451. }
  2452. WmipSetDosError(Status);
  2453. return(Status);
  2454. }
  2455. ULONG
  2456. WmipFlushLogger(
  2457. IN OUT PWMI_LOGGER_INFORMATION LoggerInfo
  2458. )
  2459. /*++
  2460. Routine Description:
  2461. This is the actual routine to communicate with the kernel to start
  2462. the logger. All the required parameters must be in LoggerInfo.
  2463. Arguments:
  2464. LoggerInfo The actual parameters to be passed to and return from
  2465. kernel.
  2466. Return Value:
  2467. The status of performing the action requested.
  2468. --*/
  2469. {
  2470. ULONG Status;
  2471. ULONG BufferSize;
  2472. PTRACE_ENABLE_CONTEXT pContext;
  2473. if ( (LoggerInfo == NULL)
  2474. || (LoggerInfo->Wnode.BufferSize < sizeof(WMI_LOGGER_INFORMATION))
  2475. || (! (LoggerInfo->Wnode.Flags & WNODE_FLAG_TRACED_GUID))) {
  2476. return WmipSetDosError(ERROR_INVALID_PARAMETER);
  2477. }
  2478. pContext = (PTRACE_ENABLE_CONTEXT) & LoggerInfo->Wnode.HistoricalContext;
  2479. if ( (pContext->InternalFlag != 0)
  2480. && (pContext->InternalFlag != EVENT_TRACE_INTERNAL_FLAG_PRIVATE)) {
  2481. // Currently only one possible InternalFlag value. This will filter
  2482. // out some bogus LoggerHandle
  2483. //
  2484. return WmipSetDosError(ERROR_INVALID_HANDLE);
  2485. }
  2486. if (LoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) {
  2487. Status = WmipSendUmLogRequest(
  2488. WmiFlushLoggerCode,
  2489. LoggerInfo
  2490. );
  2491. }
  2492. else {
  2493. Status = WmipSendWmiKMRequest( // actually start the logger here
  2494. NULL,
  2495. IOCTL_WMI_FLUSH_LOGGER,
  2496. LoggerInfo,
  2497. LoggerInfo->Wnode.BufferSize,
  2498. LoggerInfo,
  2499. LoggerInfo->Wnode.BufferSize,
  2500. &BufferSize,
  2501. NULL
  2502. );
  2503. }
  2504. return WmipSetDosError(Status);
  2505. }
  2506. #endif