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.

1917 lines
56 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. callouts.c
  5. Abstract:
  6. This is the source file that contains all the callout routines
  7. from the kernel itself. The only exception is TraceIo for DiskPerf.
  8. Author:
  9. Jee Fung Pang (jeepang) 03-Dec-1996
  10. Revision History:
  11. --*/
  12. #pragma warning(disable:4214)
  13. #pragma warning(disable:4115)
  14. #pragma warning(disable:4201)
  15. #pragma warning(disable:4127)
  16. #pragma warning(disable:4127)
  17. #include <stdio.h>
  18. #include <ntos.h>
  19. #include <zwapi.h>
  20. #ifdef NTPERF
  21. #include <ntdddisk.h>
  22. #endif
  23. #include <evntrace.h>
  24. #include "wmikmp.h"
  25. #include "tracep.h"
  26. #pragma warning(default:4214)
  27. #pragma warning(default:4115)
  28. #pragma warning(default:4201)
  29. #ifndef _WMIKM_
  30. #define _WMIKM_
  31. #endif
  32. #define MAX_FILENAME_TO_LOG 4096
  33. #define ETW_WORK_ITEM_LIMIT 64
  34. typedef struct _TRACE_FILE_WORK_ITEM {
  35. WORK_QUEUE_ITEM WorkItem;
  36. PFILE_OBJECT FileObject;
  37. ULONG BufferSize;
  38. } TRACE_FILE_WORK_ITEM, *PTRACE_FILE_WORK_ITEM;
  39. VOID
  40. FASTCALL
  41. WmipTracePageFault(
  42. IN NTSTATUS Status,
  43. IN PVOID VirtualAddress,
  44. IN PVOID TrapFrame
  45. );
  46. VOID
  47. WmipTraceNetwork(
  48. IN ULONG GroupType,
  49. IN PVOID EventInfo,
  50. IN ULONG EventInfoLen,
  51. IN PVOID Reserved
  52. );
  53. VOID
  54. WmipTraceIo(
  55. IN ULONG DiskNumber,
  56. IN PIRP Irp,
  57. IN PVOID Counters
  58. );
  59. VOID WmipTraceFile(
  60. IN PVOID TraceFileContext
  61. );
  62. VOID
  63. WmipTraceLoadImage(
  64. IN PUNICODE_STRING ImageName,
  65. IN HANDLE ProcessId,
  66. IN PIMAGE_INFO ImageInfo
  67. );
  68. VOID
  69. WmipTraceRegistry(
  70. IN NTSTATUS Status,
  71. IN PVOID Kcb,
  72. IN LONGLONG ElapsedTime,
  73. IN ULONG Index,
  74. IN PUNICODE_STRING KeyName,
  75. IN UCHAR Type
  76. );
  77. #ifdef ALLOC_PRAGMA
  78. #pragma alloc_text(PAGEWMI, WmipIsLoggerOn)
  79. #pragma alloc_text(PAGE, WmipEnableKernelTrace)
  80. #pragma alloc_text(PAGE, WmipDisableKernelTrace)
  81. #pragma alloc_text(PAGE, WmipSetTraceNotify)
  82. #pragma alloc_text(PAGE, WmiTraceProcess)
  83. #pragma alloc_text(PAGE, WmiTraceThread)
  84. #pragma alloc_text(PAGE, WmipTraceFile)
  85. #pragma alloc_text(PAGE, WmipTraceLoadImage)
  86. #pragma alloc_text(PAGE, WmipTraceRegistry)
  87. #pragma alloc_text(PAGEWMI, WmipTracePageFault)
  88. #pragma alloc_text(PAGEWMI, WmipTraceNetwork)
  89. #pragma alloc_text(PAGEWMI, WmipTraceIo)
  90. #pragma alloc_text(PAGEWMI, WmiTraceContextSwap)
  91. #pragma alloc_text(PAGE, WmiStartContextSwapTrace)
  92. #pragma alloc_text(PAGE, WmiStopContextSwapTrace)
  93. #endif
  94. ULONG WmipTraceFileFlag = FALSE;
  95. LONG WmipFileIndex = 0;
  96. LONG WmipWorkItemCounter = 0;
  97. PFILE_OBJECT *WmipFileTable = NULL;
  98. #ifdef ALLOC_DATA_PRAGMA
  99. #pragma data_seg("PAGEDATA")
  100. #endif
  101. ULONG WmipKernelLoggerStartedOnce = 0;
  102. LONG WmipTraceProcessRef = 0;
  103. PVOID WmipDiskIoNotify = NULL;
  104. PVOID WmipTdiIoNotify = NULL;
  105. #ifdef ALLOC_DATA_PRAGMA
  106. #pragma data_seg()
  107. #endif
  108. typedef struct _TRACE_DEVICE {
  109. PDEVICE_OBJECT DeviceObject;
  110. ULONG TraceClass;
  111. } TRACE_DEVICE, *PTRACE_DEVICE;
  112. VOID
  113. FASTCALL
  114. WmipEnableKernelTrace(
  115. IN ULONG EnableFlags
  116. )
  117. /*++
  118. Routine Description:
  119. This is called by WmipStartLogger in tracelog.c. Its purpose is to
  120. set up all the kernel notification routines that can produce event traces
  121. for capacity planning.
  122. Arguments:
  123. ExtendedOn a flag to indicate if extended mode tracing is requested
  124. Return Value:
  125. None
  126. --*/
  127. {
  128. PREGENTRY RegEntry;
  129. PLIST_ENTRY RegEntryList;
  130. ULONG DevicesFound;
  131. long Index, DiskFound;
  132. PTRACE_DEVICE *deviceList, device;
  133. CCHAR stackSize;
  134. PIRP irp;
  135. PVOID notifyRoutine;
  136. PIO_STACK_LOCATION irpStack;
  137. NTSTATUS status;
  138. ULONG enableDisk, enableNetwork;
  139. PAGED_CODE();
  140. //
  141. // Since we cannot do anything, we will have to count the number
  142. // of entries we need to create first, and add some buffer
  143. //
  144. DiskFound = 0;
  145. enableDisk = (EnableFlags & EVENT_TRACE_FLAG_DISK_IO);
  146. enableNetwork = (EnableFlags & EVENT_TRACE_FLAG_NETWORK_TCPIP);
  147. if ( enableDisk || enableNetwork ) {
  148. //
  149. // Setting the callouts will cause new PDO registration to be enabled
  150. // from here on.
  151. //
  152. if (enableDisk) {
  153. WmipDiskIoNotify = (PVOID) (ULONG_PTR) &WmipTraceIo;
  154. }
  155. if (enableNetwork) {
  156. WmipTdiIoNotify = (PVOID) (ULONG_PTR) &WmipTraceNetwork;
  157. }
  158. DevicesFound = WmipInUseRegEntryCount;
  159. if (DevicesFound == 0) {
  160. return;
  161. }
  162. deviceList = (PTRACE_DEVICE*)
  163. ExAllocatePoolWithTag(
  164. PagedPool,
  165. (DevicesFound) * sizeof(TRACE_DEVICE),
  166. TRACEPOOLTAG);
  167. if (deviceList == NULL) {
  168. return;
  169. }
  170. RtlZeroMemory(deviceList, sizeof(TRACE_DEVICE) * DevicesFound);
  171. //
  172. // Now, we will go through what's already in the list and enable trace
  173. // notification routine. Devices who registered while after we've set
  174. // the callout will get another Irp to enable, but that's alright
  175. //
  176. device = (PTRACE_DEVICE) deviceList; // start from first element
  177. Index = 0;
  178. WmipEnterSMCritSection();
  179. RegEntryList = WmipInUseRegEntryHead.Flink;
  180. while (RegEntryList != &WmipInUseRegEntryHead) {
  181. RegEntry = CONTAINING_RECORD(RegEntryList,REGENTRY,InUseEntryList);
  182. if (RegEntry->Flags & REGENTRY_FLAG_TRACED) {
  183. if ((ULONG) Index < DevicesFound) {
  184. device->TraceClass
  185. = RegEntry->Flags & WMIREG_FLAG_TRACE_NOTIFY_MASK;
  186. if (device->TraceClass == WMIREG_NOTIFY_DISK_IO)
  187. DiskFound++;
  188. device->DeviceObject = RegEntry->DeviceObject;
  189. device++;
  190. Index++;
  191. }
  192. }
  193. RegEntryList = RegEntryList->Flink;
  194. }
  195. WmipLeaveSMCritSection();
  196. //
  197. // actually send the notification to diskperf or tdi here
  198. //
  199. stackSize = WmipServiceDeviceObject->StackSize;
  200. irp = IoAllocateIrp(stackSize, FALSE);
  201. device = (PTRACE_DEVICE) deviceList;
  202. while (--Index >= 0 && irp != NULL) {
  203. if (device->DeviceObject != NULL) {
  204. if ( (device->TraceClass == WMIREG_NOTIFY_TDI_IO) &&
  205. enableNetwork ) {
  206. notifyRoutine = (PVOID) (ULONG_PTR) &WmipTraceNetwork;
  207. }
  208. else if ( (device->TraceClass == WMIREG_NOTIFY_DISK_IO) &&
  209. enableDisk ) {
  210. notifyRoutine = (PVOID) (ULONG_PTR) &WmipTraceIo;
  211. }
  212. else { // consider supporting generic callout for other devices
  213. notifyRoutine = NULL;
  214. device ++;
  215. continue;
  216. }
  217. do {
  218. IoInitializeIrp(irp, IoSizeOfIrp(stackSize), stackSize);
  219. IoSetNextIrpStackLocation(irp);
  220. irpStack = IoGetCurrentIrpStackLocation(irp);
  221. irpStack->DeviceObject = WmipServiceDeviceObject;
  222. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  223. status = WmipForwardWmiIrp(
  224. irp,
  225. IRP_MN_SET_TRACE_NOTIFY,
  226. IoWMIDeviceObjectToProviderId(device->DeviceObject),
  227. NULL,
  228. sizeof(notifyRoutine),
  229. &notifyRoutine
  230. );
  231. if (status == STATUS_WMI_TRY_AGAIN) {
  232. IoFreeIrp(irp);
  233. stackSize = WmipServiceDeviceObject->StackSize;
  234. irp = IoAllocateIrp(stackSize, FALSE);
  235. if (!irp) {
  236. break;
  237. }
  238. }
  239. } while (status == STATUS_WMI_TRY_AGAIN);
  240. }
  241. device++;
  242. }
  243. if (irp) {
  244. IoFreeIrp(irp);
  245. }
  246. ExFreePoolWithTag(deviceList, TRACEPOOLTAG);
  247. // free the array that we created above
  248. //
  249. }
  250. if (EnableFlags & EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS) {
  251. MmSetPageFaultNotifyRoutine(
  252. (PPAGE_FAULT_NOTIFY_ROUTINE) &WmipTracePageFault);
  253. }
  254. if (EnableFlags & EVENT_TRACE_FLAG_DISK_FILE_IO) {
  255. //
  256. // NOTE: We assume StartLogger will always reserve space for
  257. // FileTable already
  258. //
  259. WmipTraceFileFlag = TRUE;
  260. }
  261. if (EnableFlags & EVENT_TRACE_FLAG_IMAGE_LOAD) {
  262. if (!(WmipKernelLoggerStartedOnce & EVENT_TRACE_FLAG_IMAGE_LOAD)) {
  263. PsSetLoadImageNotifyRoutine(
  264. (PLOAD_IMAGE_NOTIFY_ROUTINE) &WmipTraceLoadImage
  265. );
  266. WmipKernelLoggerStartedOnce |= EVENT_TRACE_FLAG_IMAGE_LOAD;
  267. }
  268. }
  269. if (EnableFlags & EVENT_TRACE_FLAG_REGISTRY) {
  270. CmSetTraceNotifyRoutine(
  271. (PCM_TRACE_NOTIFY_ROUTINE) &WmipTraceRegistry,
  272. FALSE
  273. );
  274. }
  275. }
  276. VOID
  277. FASTCALL
  278. WmipDisableKernelTrace(
  279. IN ULONG EnableFlags
  280. )
  281. /*++
  282. Routine Description:
  283. This is called by WmipStopLogger in tracelog.c. Its purpose of the
  284. disable all the kernel notification routines that was defined by
  285. WmipEnableKernelTrace
  286. Arguments:
  287. EnableFlags Flags indicated what was enabled and needs to be disabled
  288. Return Value:
  289. None
  290. --*/
  291. {
  292. PVOID NullPtr = NULL;
  293. PREGENTRY RegEntry;
  294. PLIST_ENTRY RegEntryList;
  295. ULONG DevicesFound;
  296. long Index;
  297. PTRACE_DEVICE* deviceList, device;
  298. CCHAR stackSize;
  299. PIRP irp;
  300. PIO_STACK_LOCATION irpStack;
  301. NTSTATUS status;
  302. ULONG enableDisk, enableNetwork;
  303. PAGED_CODE();
  304. //
  305. // first, disable partition change notification
  306. //
  307. if (EnableFlags & EVENT_TRACE_FLAG_DISK_FILE_IO) {
  308. WmipTraceFileFlag = FALSE;
  309. if (WmipFileTable != NULL) {
  310. RtlZeroMemory(
  311. WmipFileTable,
  312. MAX_FILE_TABLE_SIZE * sizeof(PFILE_OBJECT));
  313. }
  314. }
  315. if (EnableFlags & EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS) {
  316. MmSetPageFaultNotifyRoutine(NULL);
  317. }
  318. if (EnableFlags & EVENT_TRACE_FLAG_REGISTRY) {
  319. CmSetTraceNotifyRoutine(NULL,TRUE);
  320. }
  321. enableDisk = (EnableFlags & EVENT_TRACE_FLAG_DISK_IO);
  322. enableNetwork = (EnableFlags & EVENT_TRACE_FLAG_NETWORK_TCPIP);
  323. if (!enableDisk && !enableNetwork)
  324. return; // NOTE: assumes all flags are already checked
  325. //
  326. // Note. Since this is in the middle is StopLogger, it is not possible
  327. // StartLogger will prevent kernel tracing from being enabled, hence
  328. // we need not worry about WmipEnableKernelTrace() being called while
  329. // this is in progress.
  330. //
  331. WmipDiskIoNotify = NULL;
  332. WmipTdiIoNotify = NULL;
  333. DevicesFound = WmipInUseRegEntryCount;
  334. deviceList = (PTRACE_DEVICE*)
  335. ExAllocatePoolWithTag(
  336. PagedPool,
  337. (DevicesFound) * sizeof(TRACE_DEVICE),
  338. TRACEPOOLTAG);
  339. if (deviceList == NULL)
  340. return;
  341. RtlZeroMemory(deviceList, sizeof(TRACE_DEVICE) * DevicesFound);
  342. Index = 0;
  343. device = (PTRACE_DEVICE) deviceList; // start from first element
  344. //
  345. // To disable we do not need to worry about TraceClass, since we simply
  346. // set all callouts to NULL
  347. //
  348. WmipEnterSMCritSection();
  349. RegEntryList = WmipInUseRegEntryHead.Flink;
  350. while (RegEntryList != &WmipInUseRegEntryHead) {
  351. RegEntry = CONTAINING_RECORD(RegEntryList, REGENTRY, InUseEntryList);
  352. if (RegEntry->Flags & REGENTRY_FLAG_TRACED) {
  353. if ((ULONG)Index < DevicesFound) {
  354. device->TraceClass
  355. = RegEntry->Flags & WMIREG_FLAG_TRACE_NOTIFY_MASK;
  356. device->DeviceObject = RegEntry->DeviceObject;
  357. device++; Index++;
  358. }
  359. }
  360. RegEntryList = RegEntryList->Flink;
  361. }
  362. WmipLeaveSMCritSection();
  363. stackSize = WmipServiceDeviceObject->StackSize;
  364. irp = IoAllocateIrp(stackSize, FALSE);
  365. device = (PTRACE_DEVICE) deviceList; // start from first element
  366. while (--Index >= 0 && irp != NULL) {
  367. if ((device->DeviceObject != NULL) &&
  368. ((device->TraceClass == WMIREG_NOTIFY_TDI_IO) ||
  369. (device->TraceClass == WMIREG_NOTIFY_DISK_IO))) {
  370. do {
  371. IoInitializeIrp(irp, IoSizeOfIrp(stackSize), stackSize);
  372. IoSetNextIrpStackLocation(irp);
  373. irpStack = IoGetCurrentIrpStackLocation(irp);
  374. irpStack->DeviceObject = WmipServiceDeviceObject;
  375. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  376. status = WmipForwardWmiIrp(
  377. irp,
  378. IRP_MN_SET_TRACE_NOTIFY,
  379. IoWMIDeviceObjectToProviderId(device->DeviceObject),
  380. NULL,
  381. sizeof(NullPtr),
  382. &NullPtr
  383. );
  384. if (status == STATUS_WMI_TRY_AGAIN) {
  385. IoFreeIrp(irp);
  386. stackSize = WmipServiceDeviceObject->StackSize;
  387. irp = IoAllocateIrp(stackSize, FALSE);
  388. if (!irp) {
  389. break;
  390. }
  391. }
  392. else {
  393. break;
  394. }
  395. } while (TRUE);
  396. }
  397. device++;
  398. }
  399. if (irp) {
  400. IoFreeIrp(irp);
  401. }
  402. ExFreePoolWithTag(deviceList, TRACEPOOLTAG);
  403. }
  404. VOID
  405. WmipSetTraceNotify(
  406. IN PDEVICE_OBJECT DeviceObject,
  407. IN ULONG TraceClass,
  408. IN ULONG Enable
  409. )
  410. {
  411. PIRP irp;
  412. PVOID NotifyRoutine = NULL;
  413. NTSTATUS status;
  414. CCHAR stackSize;
  415. PIO_STACK_LOCATION irpStack;
  416. if (Enable) {
  417. switch (TraceClass) {
  418. case WMIREG_NOTIFY_DISK_IO :
  419. NotifyRoutine = WmipDiskIoNotify;
  420. break;
  421. case WMIREG_NOTIFY_TDI_IO :
  422. NotifyRoutine = WmipTdiIoNotify;
  423. break;
  424. default :
  425. return;
  426. }
  427. if (NotifyRoutine == NULL) // trace not enabled, so do not
  428. return; // send any Irp to enable
  429. }
  430. do {
  431. stackSize = WmipServiceDeviceObject->StackSize;
  432. irp = IoAllocateIrp(stackSize, FALSE);
  433. if (!irp)
  434. return;
  435. IoSetNextIrpStackLocation(irp);
  436. irpStack = IoGetCurrentIrpStackLocation(irp);
  437. irpStack->DeviceObject = WmipServiceDeviceObject;
  438. status = WmipForwardWmiIrp(
  439. irp,
  440. IRP_MN_SET_TRACE_NOTIFY,
  441. IoWMIDeviceObjectToProviderId(DeviceObject),
  442. NULL,
  443. sizeof(NotifyRoutine),
  444. &NotifyRoutine
  445. );
  446. IoFreeIrp(irp);
  447. } while (status == STATUS_WMI_TRY_AGAIN);
  448. }
  449. //
  450. // All the following routines are callout or notification routines for
  451. // generating kernel event traces
  452. //
  453. NTKERNELAPI
  454. VOID
  455. FASTCALL
  456. WmiTraceProcess(
  457. IN PEPROCESS Process,
  458. IN BOOLEAN Create
  459. )
  460. /*++
  461. Routine Description:
  462. This callout routine is called from ps\create.c and ps\psdelete.c.
  463. Arguments:
  464. Process - PEPROCESS;
  465. Create - True if intended process is being created.
  466. Return Value:
  467. None
  468. --*/
  469. {
  470. ULONG Size, LoggerId;
  471. NTSTATUS Status;
  472. PCHAR AuxPtr;
  473. PSYSTEM_TRACE_HEADER Header;
  474. PVOID BufferResource;
  475. ULONG SidLength = sizeof(ULONG);
  476. PTOKEN_USER LocalUser = NULL;
  477. PWMI_PROCESS_INFORMATION ProcessInfo;
  478. PWMI_LOGGER_CONTEXT LoggerContext;
  479. PVOID Token;
  480. PUNICODE_STRING pImageFileName;
  481. ANSI_STRING AnsiImageFileName;
  482. ULONG ImageLength, ImageOnlyLength;
  483. PCHAR Src;
  484. PCHAR Dst;
  485. ULONG LongImageName;
  486. #if DBG
  487. LONG RefCount;
  488. #endif
  489. PAGED_CODE();
  490. if ((WmipIsLoggerOn(WmipKernelLogger) == NULL) &&
  491. (WmipIsLoggerOn(WmipEventLogger) == NULL))
  492. return;
  493. Token = PsReferencePrimaryToken(Process);
  494. if (Token != NULL) {
  495. Status = SeQueryInformationToken(
  496. Token,
  497. TokenUser,
  498. &LocalUser);
  499. PsDereferencePrimaryTokenEx (Process, Token);
  500. } else {
  501. Status = STATUS_SEVERITY_ERROR;
  502. }
  503. if (NT_SUCCESS(Status)) {
  504. WmipAssert(LocalUser != NULL); // temporary for SE folks
  505. if (LocalUser != NULL) {
  506. SidLength = SeLengthSid(LocalUser->User.Sid) + sizeof(TOKEN_USER);
  507. }
  508. } else {
  509. SidLength = sizeof(ULONG);
  510. LocalUser = NULL;
  511. }
  512. AnsiImageFileName.Buffer = NULL;
  513. // Get image name not limited to 16 chars.
  514. Status = SeLocateProcessImageName (Process, &pImageFileName);
  515. if (NT_SUCCESS (Status)) {
  516. ImageLength = pImageFileName->Length;
  517. if (ImageLength != 0) {
  518. Status = RtlUnicodeStringToAnsiString(&AnsiImageFileName, pImageFileName, TRUE);
  519. if (NT_SUCCESS (Status)) {
  520. ImageLength = AnsiImageFileName.Length;
  521. } else {
  522. ImageLength = 0;
  523. }
  524. }
  525. ExFreePool (pImageFileName);
  526. } else {
  527. ImageLength = 0;
  528. }
  529. // if ImageLength == 0, AnsiImageFileName has not been allocated at this point.
  530. if (ImageLength != 0) {
  531. Src = AnsiImageFileName.Buffer + ImageLength;
  532. while (Src != AnsiImageFileName.Buffer) {
  533. if (*--Src == '\\') {
  534. Src = Src + 1;
  535. break;
  536. }
  537. }
  538. ImageOnlyLength = ImageLength - (ULONG)(Src - AnsiImageFileName.Buffer);
  539. ImageLength = ImageOnlyLength + 1;
  540. LongImageName = TRUE;
  541. } else {
  542. Src = (PCHAR) Process->ImageFileName;
  543. // Process->ImageFileName is max 16 chars and always NULL-terminated.
  544. ImageLength = (ULONG) strlen (Src);
  545. if (ImageLength != 0) {
  546. ImageLength++;
  547. }
  548. LongImageName = FALSE;
  549. ImageOnlyLength = 0;
  550. }
  551. // if LongImageName == FALSE, AnsiImageFileName has not been allocated at this point.
  552. Size = SidLength + FIELD_OFFSET(WMI_PROCESS_INFORMATION, Sid) + ImageLength;
  553. for (LoggerId = 0; LoggerId < MAXLOGGERS; LoggerId++) {
  554. if (LoggerId != WmipKernelLogger && LoggerId != WmipEventLogger) {
  555. continue;
  556. }
  557. #if DBG
  558. RefCount =
  559. #endif
  560. WmipReferenceLogger(LoggerId);
  561. TraceDebug((4, "WmiTraceProcess: %d %d->%d\n",
  562. LoggerId, RefCount-1, RefCount));
  563. LoggerContext = WmipIsLoggerOn(LoggerId);
  564. if (LoggerContext != NULL) {
  565. if (LoggerContext->EnableFlags & EVENT_TRACE_FLAG_PROCESS) {
  566. Header = WmiReserveWithSystemHeader( LoggerId,
  567. Size,
  568. NULL,
  569. &BufferResource);
  570. if (Header) {
  571. if(Create) {
  572. Header->Packet.HookId = WMI_LOG_TYPE_PROCESS_CREATE;
  573. } else {
  574. Header->Packet.HookId = WMI_LOG_TYPE_PROCESS_DELETE;
  575. }
  576. ProcessInfo = (PWMI_PROCESS_INFORMATION) (Header + 1);
  577. ProcessInfo->PageDirectoryBase = MmGetDirectoryFrameFromProcess(Process);
  578. ProcessInfo->ProcessId = HandleToUlong(Process->UniqueProcessId);
  579. ProcessInfo->ParentId = HandleToUlong(Process->InheritedFromUniqueProcessId);
  580. ProcessInfo->SessionId = MmGetSessionId (Process);
  581. ProcessInfo->ExitStatus = (Create ? STATUS_SUCCESS : Process->ExitStatus);
  582. AuxPtr = (PCHAR) (&ProcessInfo->Sid);
  583. if (LocalUser != NULL) {
  584. RtlCopyMemory(AuxPtr, LocalUser, SidLength);
  585. } else {
  586. *((PULONG) AuxPtr) = 0;
  587. }
  588. AuxPtr += SidLength;
  589. if (ImageLength != 0) {
  590. Dst = AuxPtr;
  591. if (LongImageName) {
  592. // ImageOnlyLength is from SeLocateProcessImageName(),
  593. // so we can trust it.
  594. RtlCopyMemory (Dst, Src, ImageOnlyLength);
  595. Dst += ImageOnlyLength;
  596. *Dst++ = '\0';
  597. } else {
  598. // Copy 16 char name. Src is alwasy NULL-terminated.
  599. while (*Dst++ = *Src++) {
  600. ;
  601. }
  602. }
  603. }
  604. WmipReleaseTraceBuffer(BufferResource, LoggerContext);
  605. }
  606. }
  607. }
  608. #if DBG
  609. RefCount =
  610. #endif
  611. WmipDereferenceLogger(LoggerId);
  612. TraceDebug((4, "WmiTraceProcess: %d %d->%d\n",
  613. LoggerId, RefCount+1, RefCount));
  614. }
  615. if (LongImageName) {
  616. RtlFreeAnsiString (&AnsiImageFileName);
  617. }
  618. if (LocalUser != NULL) {
  619. ExFreePool(LocalUser);
  620. }
  621. }
  622. NTKERNELAPI
  623. VOID
  624. WmiTraceThread(
  625. IN PETHREAD Thread,
  626. IN PINITIAL_TEB InitialTeb OPTIONAL,
  627. IN BOOLEAN Create
  628. )
  629. /*++
  630. Routine Description:
  631. This callout routine is called from ps\create.c and ps\psdelete.c.
  632. It is a PCREATE_THREAD_NOTIFY_ROUTINE.
  633. Arguments:
  634. Thread - PETHREAD structure
  635. InitialTeb - PINITIAL_TEB
  636. Create - True if intended thread is being created.
  637. Return Value:
  638. None
  639. --*/
  640. {
  641. ULONG LoggerId;
  642. PSYSTEM_TRACE_HEADER Header;
  643. PVOID BufferResource;
  644. PWMI_LOGGER_CONTEXT LoggerContext;
  645. #if DBG
  646. LONG RefCount;
  647. #endif
  648. PAGED_CODE();
  649. if ((WmipIsLoggerOn(WmipKernelLogger) == NULL) &&
  650. (WmipIsLoggerOn(WmipEventLogger) == NULL)) {
  651. return;
  652. }
  653. for (LoggerId = 0; LoggerId < MAXLOGGERS; LoggerId++) {
  654. if (LoggerId != WmipKernelLogger && LoggerId != WmipEventLogger) {
  655. continue;
  656. }
  657. #if DBG
  658. RefCount =
  659. #endif
  660. WmipReferenceLogger(LoggerId);
  661. TraceDebug((4, "WmiTraceThread: %d %d->%d\n",
  662. LoggerId, RefCount-1, RefCount));
  663. LoggerContext = WmipIsLoggerOn(LoggerId);
  664. if (LoggerContext != NULL) {
  665. if (LoggerContext->EnableFlags & EVENT_TRACE_FLAG_THREAD) {
  666. if (Create) {
  667. PWMI_EXTENDED_THREAD_INFORMATION ThreadInfo;
  668. Header = (PSYSTEM_TRACE_HEADER)
  669. WmiReserveWithSystemHeader( LoggerId,
  670. sizeof(WMI_EXTENDED_THREAD_INFORMATION),
  671. NULL,
  672. &BufferResource);
  673. if (Header) {
  674. Header->Packet.HookId = WMI_LOG_TYPE_THREAD_CREATE;
  675. ThreadInfo = (PWMI_EXTENDED_THREAD_INFORMATION) (Header + 1);
  676. ThreadInfo->ProcessId = HandleToUlong(Thread->Cid.UniqueProcess);
  677. ThreadInfo->ThreadId = HandleToUlong(Thread->Cid.UniqueThread);
  678. ThreadInfo->StackBase = Thread->Tcb.StackBase;
  679. ThreadInfo->StackLimit = Thread->Tcb.StackLimit;
  680. if (InitialTeb != NULL) {
  681. if ((InitialTeb->OldInitialTeb.OldStackBase == NULL) &&
  682. (InitialTeb->OldInitialTeb.OldStackLimit == NULL)) {
  683. ThreadInfo->UserStackBase = InitialTeb->StackBase;
  684. ThreadInfo->UserStackLimit = InitialTeb->StackLimit;
  685. } else {
  686. ThreadInfo->UserStackBase = InitialTeb->OldInitialTeb.OldStackBase;
  687. ThreadInfo->UserStackLimit = InitialTeb->OldInitialTeb.OldStackLimit;
  688. }
  689. } else {
  690. ThreadInfo->UserStackBase = NULL;
  691. ThreadInfo->UserStackLimit = NULL;
  692. }
  693. ThreadInfo->StartAddr = (Thread)->StartAddress;
  694. ThreadInfo->Win32StartAddr = (Thread)->Win32StartAddress;
  695. ThreadInfo->WaitMode = -1;
  696. WmipReleaseTraceBuffer(BufferResource, LoggerContext);
  697. }
  698. } else {
  699. PWMI_THREAD_INFORMATION ThreadInfo;
  700. Header = (PSYSTEM_TRACE_HEADER)
  701. WmiReserveWithSystemHeader( LoggerId,
  702. sizeof(WMI_THREAD_INFORMATION),
  703. NULL,
  704. &BufferResource);
  705. if (Header) {
  706. Header->Packet.HookId = WMI_LOG_TYPE_THREAD_DELETE;
  707. ThreadInfo = (PWMI_THREAD_INFORMATION) (Header + 1);
  708. ThreadInfo->ProcessId = HandleToUlong((Thread)->Cid.UniqueProcess);
  709. ThreadInfo->ThreadId = HandleToUlong((Thread)->Cid.UniqueThread);
  710. WmipReleaseTraceBuffer(BufferResource, LoggerContext);
  711. }
  712. }
  713. }
  714. }
  715. #if DBG
  716. RefCount =
  717. #endif
  718. WmipDereferenceLogger(LoggerId);
  719. TraceDebug((4, "WmiTraceThread: %d %d->%d\n",
  720. LoggerId, RefCount+1, RefCount));
  721. }
  722. }
  723. VOID
  724. FASTCALL
  725. WmipTracePageFault(
  726. IN NTSTATUS Status,
  727. IN PVOID VirtualAddress,
  728. IN PVOID TrapFrame
  729. )
  730. /*++
  731. Routine Description:
  732. This callout routine is called from mm\mmfault.c.
  733. It is a PPAGE_FAULT_NOTIFY_ROUTINE
  734. Arguments:
  735. Status Used to tell the type of fault
  736. VirtualAddress The virtual address responsible for the fault
  737. TrapFrame Trap Frame
  738. Return Value:
  739. None
  740. --*/
  741. {
  742. UCHAR Type;
  743. PVOID *AuxInfo;
  744. PSYSTEM_TRACE_HEADER Header;
  745. PVOID BufferResource;
  746. PWMI_LOGGER_CONTEXT LoggerContext;
  747. if (Status == STATUS_PAGE_FAULT_DEMAND_ZERO)
  748. Type = EVENT_TRACE_TYPE_MM_DZF;
  749. else if (Status == STATUS_PAGE_FAULT_TRANSITION)
  750. Type = EVENT_TRACE_TYPE_MM_TF;
  751. else if (Status == STATUS_PAGE_FAULT_COPY_ON_WRITE)
  752. Type = EVENT_TRACE_TYPE_MM_COW;
  753. else if (Status == STATUS_PAGE_FAULT_PAGING_FILE)
  754. Type = EVENT_TRACE_TYPE_MM_HPF;
  755. else if (Status == STATUS_PAGE_FAULT_GUARD_PAGE)
  756. Type = EVENT_TRACE_TYPE_MM_GPF;
  757. else {
  758. #if DBG
  759. DbgPrintEx(DPFLTR_WMILIB_ID,
  760. DPFLTR_INFO_LEVEL,
  761. "WmipTracePageFault: Skipping fault %X\n",
  762. Status);
  763. #endif
  764. return;
  765. }
  766. LoggerContext = WmipIsLoggerOn(WmipKernelLogger);
  767. if (LoggerContext == NULL) {
  768. return;
  769. }
  770. Header = (PSYSTEM_TRACE_HEADER)
  771. WmiReserveWithSystemHeader(
  772. WmipKernelLogger,
  773. 2 * sizeof(PVOID),
  774. NULL,
  775. &BufferResource);
  776. if (Header == NULL)
  777. return;
  778. Header->Packet.Group = (UCHAR) (EVENT_TRACE_GROUP_MEMORY >> 8);
  779. Header->Packet.Type = Type;
  780. AuxInfo = (PVOID*) ((PCHAR)Header + sizeof(SYSTEM_TRACE_HEADER));
  781. AuxInfo[0] = VirtualAddress;
  782. AuxInfo[1] = 0;
  783. if (TrapFrame != NULL) {
  784. #ifdef _X86_
  785. AuxInfo[1] = (PVOID) ((PKTRAP_FRAME)TrapFrame)->Eip;
  786. #endif
  787. #ifdef _IA64_
  788. AuxInfo[1] = (PVOID) ((PKTRAP_FRAME)TrapFrame)->StIIP;
  789. #endif
  790. #ifdef _AMD64_
  791. AuxInfo[1] = (PVOID) ((PKTRAP_FRAME)TrapFrame)->Rip;
  792. #endif
  793. }
  794. WmipReleaseTraceBuffer(BufferResource, LoggerContext);
  795. return;
  796. }
  797. VOID
  798. WmipTraceNetwork(
  799. IN ULONG GroupType, // Group/type for the event
  800. IN PVOID EventInfo, // Event data as defined in MOF
  801. IN ULONG EventInfoLen, // Length of the event data
  802. IN PVOID Reserved // not used
  803. )
  804. /*++
  805. Routine Description:
  806. This callout routine is called from tcpip.sys to log a network event.
  807. Arguments:
  808. GroupType a ULONG key to indicate the action
  809. EventInfo a pointer to contiguous memory containing information
  810. to be attached to event trace
  811. EventInfoLen length of EventInfo
  812. Reserved Not used.
  813. Return Value:
  814. None
  815. --*/
  816. {
  817. PPERFINFO_TRACE_HEADER Header;
  818. PWMI_BUFFER_HEADER BufferResource;
  819. PWMI_LOGGER_CONTEXT LoggerContext;
  820. UNREFERENCED_PARAMETER (Reserved);
  821. LoggerContext = WmipLoggerContext[WmipKernelLogger];
  822. Header = WmiReserveWithPerfHeader(EventInfoLen, &BufferResource);
  823. if (Header == NULL) {
  824. return;
  825. }
  826. Header->Packet.HookId = (USHORT) GroupType;
  827. RtlCopyMemory((PUCHAR)Header + FIELD_OFFSET(PERFINFO_TRACE_HEADER, Data),
  828. EventInfo,
  829. EventInfoLen);
  830. WmipReleaseTraceBuffer(BufferResource, LoggerContext);
  831. return;
  832. }
  833. VOID
  834. WmipTraceIo(
  835. IN ULONG DiskNumber,
  836. IN PIRP Irp,
  837. IN PVOID Counters // use PDISK_PERFORMANCE if we need it
  838. )
  839. /*++
  840. Routine Description:
  841. This callout routine is called from DiskPerf
  842. It is a PPHYSICAL_DISK_IO_NOTIFY_ROUTINE
  843. Arguments:
  844. DiskNumber The disk number assigned by DiskPerf
  845. CurrentIrpStack The Irp stack location that DiskPerf is at
  846. Irp The Irp that is being passed through DiskPerf
  847. Return Value:
  848. None
  849. --*/
  850. {
  851. PIO_STACK_LOCATION CurrentIrpStack = IoGetCurrentIrpStackLocation(Irp);
  852. WMI_DISKIO_READWRITE *IoTrace;
  853. ULONG Size;
  854. PLARGE_INTEGER IoResponse;
  855. PSYSTEM_TRACE_HEADER Header;
  856. PVOID BufferResource;
  857. PWMI_LOGGER_CONTEXT LoggerContext;
  858. ULONG FileTraceOn = WmipTraceFileFlag;
  859. PFILE_OBJECT fileObject = NULL;
  860. PTRACE_FILE_WORK_ITEM TraceFileWorkQueueItem;
  861. NTSTATUS Status;
  862. UNREFERENCED_PARAMETER(Counters);
  863. Size = sizeof(struct _WMI_DISKIO_READWRITE);
  864. LoggerContext = WmipIsLoggerOn(WmipKernelLogger);
  865. if (LoggerContext == NULL) {
  866. return;
  867. }
  868. Header = (PSYSTEM_TRACE_HEADER)
  869. WmiReserveWithSystemHeader(
  870. WmipKernelLogger,
  871. Size,
  872. Irp->Tail.Overlay.Thread,
  873. &BufferResource);
  874. if (Header == NULL) {
  875. return;
  876. }
  877. Header->Packet.Group = (UCHAR) (EVENT_TRACE_GROUP_IO >> 8);
  878. if (CurrentIrpStack->MajorFunction == IRP_MJ_READ)
  879. Header->Packet.Type = EVENT_TRACE_TYPE_IO_READ;
  880. else
  881. Header->Packet.Type = EVENT_TRACE_TYPE_IO_WRITE;
  882. IoTrace = (struct _WMI_DISKIO_READWRITE *)
  883. ((PCHAR) Header + sizeof(SYSTEM_TRACE_HEADER));
  884. IoResponse = (PLARGE_INTEGER) &CurrentIrpStack->Parameters.Read;
  885. IoTrace->DiskNumber = DiskNumber;
  886. IoTrace->IrpFlags = Irp->Flags;
  887. IoTrace->Size = (ULONG) Irp->IoStatus.Information;
  888. IoTrace->ByteOffset = CurrentIrpStack->Parameters.Read.ByteOffset.QuadPart;
  889. IoTrace->ResponseTime = (ULONG) IoResponse->QuadPart;
  890. if (IoResponse->HighPart == 0) {
  891. IoTrace->ResponseTime = IoResponse->LowPart;
  892. } else {
  893. IoTrace->ResponseTime = 0xFFFFFFFF;
  894. }
  895. IoTrace->HighResResponseTime = IoResponse->QuadPart;
  896. if (FileTraceOn) {
  897. PFILE_OBJECT *fileTable;
  898. ULONG i;
  899. ULONG LoggerId;
  900. ULONG currentValue, newValue, retValue;
  901. #if DBG
  902. LONG RefCount;
  903. #endif
  904. if (Irp->Flags & IRP_ASSOCIATED_IRP) {
  905. PIRP AssociatedIrp = Irp->AssociatedIrp.MasterIrp;
  906. if (AssociatedIrp != NULL) {
  907. fileObject = AssociatedIrp->Tail.Overlay.OriginalFileObject;
  908. }
  909. } else {
  910. fileObject = Irp->Tail.Overlay.OriginalFileObject;
  911. }
  912. IoTrace->FileObject = fileObject;
  913. //
  914. // We are done with the IO Hook. Release the Buffer but take
  915. // a refcount on the logger context so that the fileTable
  916. // does not go away.
  917. //
  918. LoggerId = LoggerContext->LoggerId;
  919. #if DBG
  920. RefCount =
  921. #endif
  922. WmipReferenceLogger(LoggerId);
  923. TraceDebug((4, "WmiTraceFile: %d %d->%d\n",
  924. LoggerId, RefCount-1, RefCount));
  925. WmipReleaseTraceBuffer(BufferResource, LoggerContext);
  926. //
  927. // Rules for validating a file object.
  928. //
  929. // 1. File obejct cannot be NULL.
  930. // 2. Thread field in the IRP cannot be NULL.
  931. // 3. We log only paging and user mode IO.
  932. fileTable = (PFILE_OBJECT *) WmipFileTable;
  933. if ( (fileObject == NULL) ||
  934. (Irp->Tail.Overlay.Thread == NULL) ||
  935. ((!(Irp->Flags & IRP_PAGING_IO)) && (Irp->RequestorMode != UserMode)) ||
  936. (fileTable == NULL) ||
  937. (fileObject->FileName.Length == 0) ) {
  938. #if DBG
  939. RefCount =
  940. #endif
  941. WmipDereferenceLogger(LoggerId);
  942. TraceDebug((4, "WmiTraceFile: %d %d->%d\n",
  943. LoggerId, RefCount+1, RefCount));
  944. return;
  945. }
  946. //
  947. // File Cache: WmipFileIndex points to a slot for next entry.
  948. // Start with previous index and scan the table backwards.
  949. // If found, return else queue work item after checking max work
  950. // item limit.
  951. //
  952. currentValue = WmipFileIndex;
  953. for (i=0; i <MAX_FILE_TABLE_SIZE; i++) {
  954. if (currentValue == 0) {
  955. currentValue = MAX_FILE_TABLE_SIZE - 1;
  956. }
  957. else {
  958. currentValue--;
  959. }
  960. if (fileTable[currentValue] == fileObject) {
  961. //
  962. // CacheHit
  963. //
  964. #if DBG
  965. RefCount =
  966. #endif
  967. WmipDereferenceLogger(LoggerId);
  968. TraceDebug((4, "WmiTraceFile: %d %d->%d\n",
  969. LoggerId, RefCount+1, RefCount));
  970. return;
  971. }
  972. }
  973. //
  974. // Cache Miss: First check for work item queue throttle
  975. //
  976. retValue = WmipWorkItemCounter;
  977. do {
  978. currentValue = retValue;
  979. if (currentValue == ETW_WORK_ITEM_LIMIT) {
  980. #if DBG
  981. RefCount =
  982. #endif
  983. WmipDereferenceLogger(LoggerId);
  984. TraceDebug((4, "WmiTraceFile: %d %d->%d\n",
  985. LoggerId, RefCount+1, RefCount));
  986. return;
  987. } else {
  988. newValue = currentValue + 1;
  989. }
  990. retValue = InterlockedCompareExchange(&WmipWorkItemCounter, newValue, currentValue);
  991. } while (currentValue != retValue);
  992. //
  993. // Cache Miss: Simply kick out the next item based on global index
  994. // while ensuring that the WmipFileIndex is always in range.
  995. //
  996. retValue = WmipFileIndex;
  997. do {
  998. currentValue = retValue;
  999. if (currentValue == (MAX_FILE_TABLE_SIZE - 1)) {
  1000. newValue = 0;
  1001. } else {
  1002. newValue = currentValue + 1;
  1003. }
  1004. retValue = InterlockedCompareExchange(&WmipFileIndex, newValue, currentValue);
  1005. } while (currentValue != retValue);
  1006. //
  1007. // Allocate additional memory (upto 4K) with the work item allocation.
  1008. // This space is used in WmipTraceFile for ObQueryNameString call
  1009. //
  1010. TraceFileWorkQueueItem = ExAllocatePoolWithTag(NonPagedPool,
  1011. MAX_FILENAME_TO_LOG,
  1012. TRACEPOOLTAG);
  1013. if (TraceFileWorkQueueItem == NULL) {
  1014. InterlockedDecrement(&WmipWorkItemCounter);
  1015. #if DBG
  1016. RefCount =
  1017. #endif
  1018. WmipDereferenceLogger(LoggerId);
  1019. TraceDebug((4, "WmiTraceFile: %d %d->%d\n",
  1020. LoggerId, RefCount+1, RefCount));
  1021. return;
  1022. }
  1023. Status = ObReferenceObjectByPointer (
  1024. fileObject,
  1025. 0L,
  1026. IoFileObjectType,
  1027. KernelMode
  1028. );
  1029. if (!NT_SUCCESS(Status)) {
  1030. ExFreePool(TraceFileWorkQueueItem);
  1031. InterlockedDecrement(&WmipWorkItemCounter);
  1032. #if DBG
  1033. RefCount =
  1034. #endif
  1035. WmipDereferenceLogger(LoggerId);
  1036. TraceDebug((4, "WmiTraceFile: %d %d->%d\n",
  1037. LoggerId, RefCount+1, RefCount));
  1038. return;
  1039. }
  1040. ExInitializeWorkItem(
  1041. &TraceFileWorkQueueItem->WorkItem,
  1042. WmipTraceFile,
  1043. TraceFileWorkQueueItem
  1044. );
  1045. TraceFileWorkQueueItem->FileObject = fileObject;
  1046. TraceFileWorkQueueItem->BufferSize = MAX_FILENAME_TO_LOG;
  1047. //
  1048. // Insert the fileObject into the table before queuing work item
  1049. //
  1050. ASSERT(retValue < MAX_FILE_TABLE_SIZE);
  1051. fileTable[retValue] = fileObject;
  1052. #if DBG
  1053. RefCount =
  1054. #endif
  1055. WmipDereferenceLogger(LoggerId);
  1056. TraceDebug((4, "WmiTraceFile: %d %d->%d\n",
  1057. LoggerId, RefCount+1, RefCount));
  1058. ExQueueWorkItem(
  1059. &TraceFileWorkQueueItem->WorkItem,
  1060. DelayedWorkQueue
  1061. );
  1062. }
  1063. else {
  1064. WmipReleaseTraceBuffer(BufferResource, LoggerContext);
  1065. }
  1066. return;
  1067. }
  1068. VOID WmipTraceFile(
  1069. IN PVOID TraceFileContext
  1070. )
  1071. {
  1072. ULONG len;
  1073. PFILE_OBJECT fileObject;
  1074. PUNICODE_STRING fileName;
  1075. PPERFINFO_TRACE_HEADER Header;
  1076. PWMI_BUFFER_HEADER BufferResource;
  1077. PUCHAR AuxPtr;
  1078. PWMI_LOGGER_CONTEXT LoggerContext;
  1079. NTSTATUS Status;
  1080. POBJECT_NAME_INFORMATION FileNameInfo;
  1081. ULONG FileNameInfoOffset, ReturnLen;
  1082. PTRACE_FILE_WORK_ITEM WorkItem = (PTRACE_FILE_WORK_ITEM) TraceFileContext;
  1083. #if DBG
  1084. LONG RefCount;
  1085. #endif
  1086. PAGED_CODE();
  1087. FileNameInfoOffset = (ULONG) ALIGN_TO_POWER2(sizeof(TRACE_FILE_WORK_ITEM), WmiTraceAlignment);
  1088. FileNameInfo = (POBJECT_NAME_INFORMATION) ((PUCHAR)TraceFileContext +
  1089. FileNameInfoOffset);
  1090. fileObject = WorkItem->FileObject;
  1091. ASSERT(fileObject != NULL);
  1092. ASSERT(WorkItem->BufferSize > FileNameInfoOffset);
  1093. Status = ObQueryNameString( fileObject,
  1094. FileNameInfo,
  1095. WorkItem->BufferSize - FileNameInfoOffset,
  1096. &ReturnLen
  1097. );
  1098. ObDereferenceObject(fileObject);
  1099. if (NT_SUCCESS (Status)) {
  1100. fileName = &FileNameInfo->Name;
  1101. len = fileName->Length;
  1102. if ((len > 0) && (fileName->Buffer != NULL)) {
  1103. ULONG LoggerId = WmipKernelLogger;
  1104. if (LoggerId < MAXLOGGERS) {
  1105. #if DBG
  1106. RefCount =
  1107. #endif
  1108. WmipReferenceLogger(LoggerId);
  1109. TraceDebug((4, "WmipTraceFile: %d %d->%d\n",
  1110. LoggerId, RefCount-1, RefCount));
  1111. LoggerContext = WmipIsLoggerOn(LoggerId);
  1112. if (LoggerContext != NULL) {
  1113. Header = WmiReserveWithPerfHeader(
  1114. sizeof(PFILE_OBJECT) + len + sizeof(WCHAR),
  1115. &BufferResource);
  1116. if (Header != NULL) {
  1117. Header->Packet.Group = (UCHAR)(EVENT_TRACE_GROUP_FILE >> 8);
  1118. Header->Packet.Type = EVENT_TRACE_TYPE_INFO;
  1119. AuxPtr = (PUCHAR)Header +
  1120. FIELD_OFFSET(PERFINFO_TRACE_HEADER, Data);
  1121. *((PFILE_OBJECT*)AuxPtr) = fileObject;
  1122. AuxPtr += sizeof(PFILE_OBJECT);
  1123. RtlCopyMemory(AuxPtr, fileName->Buffer, len);
  1124. AuxPtr += len;
  1125. *((PWCHAR) AuxPtr) = UNICODE_NULL; // always put a NULL
  1126. WmipReleaseTraceBuffer(BufferResource, LoggerContext);
  1127. }
  1128. }
  1129. #if DBG
  1130. RefCount =
  1131. #endif
  1132. WmipDereferenceLogger(LoggerId);
  1133. TraceDebug((4, "WmiTraceThread: %d %d->%d\n",
  1134. LoggerId, RefCount+1, RefCount));
  1135. }
  1136. }
  1137. }
  1138. ExFreePool(TraceFileContext);
  1139. InterlockedDecrement(&WmipWorkItemCounter);
  1140. }
  1141. VOID
  1142. WmipTraceLoadImage(
  1143. IN PUNICODE_STRING ImageName,
  1144. IN HANDLE ProcessId,
  1145. IN PIMAGE_INFO ImageInfo
  1146. )
  1147. {
  1148. PSYSTEM_TRACE_HEADER Header;
  1149. PUCHAR AuxInfo;
  1150. PVOID BufferResource;
  1151. ULONG Length, LoggerId;
  1152. PWMI_LOGGER_CONTEXT LoggerContext;
  1153. #if DBG
  1154. LONG RefCount;
  1155. #endif
  1156. PAGED_CODE();
  1157. UNREFERENCED_PARAMETER(ProcessId);
  1158. if ((WmipIsLoggerOn(WmipKernelLogger) == NULL) &&
  1159. (WmipIsLoggerOn(WmipEventLogger) == NULL)) {
  1160. return;
  1161. }
  1162. if (ImageName == NULL) {
  1163. return;
  1164. }
  1165. Length = ImageName->Length;
  1166. if ((Length == 0) || (ImageName->Buffer == NULL)) {
  1167. return;
  1168. }
  1169. for (LoggerId = 0; LoggerId < MAXLOGGERS; LoggerId++) {
  1170. if (LoggerId != WmipKernelLogger && LoggerId != WmipEventLogger) {
  1171. continue;
  1172. }
  1173. #if DBG
  1174. RefCount =
  1175. #endif
  1176. WmipReferenceLogger(LoggerId);
  1177. TraceDebug((4, "WmipTraceLoadImage: %d %d->%d\n",
  1178. LoggerId, RefCount-1, RefCount));
  1179. LoggerContext = WmipIsLoggerOn(LoggerId);
  1180. if (LoggerContext != NULL) {
  1181. if (LoggerContext->EnableFlags & EVENT_TRACE_FLAG_IMAGE_LOAD) {
  1182. PWMI_IMAGELOAD_INFORMATION ImageLoadInfo;
  1183. Header = WmiReserveWithSystemHeader(
  1184. LoggerId,
  1185. FIELD_OFFSET (WMI_IMAGELOAD_INFORMATION, FileName) + Length + sizeof(WCHAR),
  1186. NULL,
  1187. &BufferResource);
  1188. if (Header != NULL) {
  1189. Header->Packet.HookId = WMI_LOG_TYPE_PROCESS_LOAD_IMAGE;
  1190. ImageLoadInfo = (PWMI_IMAGELOAD_INFORMATION) (Header + 1);
  1191. ImageLoadInfo->ImageBase = ImageInfo->ImageBase;
  1192. ImageLoadInfo->ImageSize = ImageInfo->ImageSize;
  1193. ImageLoadInfo->ProcessId = HandleToUlong(ProcessId);
  1194. AuxInfo = (PUCHAR) &(ImageLoadInfo->FileName[0]);
  1195. RtlCopyMemory(AuxInfo, ImageName->Buffer, Length);
  1196. AuxInfo += Length;
  1197. *((PWCHAR) AuxInfo) = UNICODE_NULL; // put a trailing NULL
  1198. WmipReleaseTraceBuffer(BufferResource, LoggerContext);
  1199. }
  1200. }
  1201. }
  1202. #if DBG
  1203. RefCount =
  1204. #endif
  1205. WmipDereferenceLogger(LoggerId);
  1206. TraceDebug((4, "WmipTraceLoadImage: %d %d->%d\n",
  1207. LoggerId, RefCount+1, RefCount));
  1208. }
  1209. PerfInfoFlushProfileCache();
  1210. }
  1211. VOID
  1212. WmipTraceRegistry(
  1213. IN NTSTATUS Status,
  1214. IN PVOID Kcb,
  1215. IN LONGLONG ElapsedTime,
  1216. IN ULONG Index,
  1217. IN PUNICODE_STRING KeyName,
  1218. IN UCHAR Type
  1219. )
  1220. /*++
  1221. Routine Description:
  1222. This routine is called to trace out registry calls
  1223. Arguments:
  1224. Return Value:
  1225. None
  1226. --*/
  1227. {
  1228. PCHAR EventInfo;
  1229. PSYSTEM_TRACE_HEADER Header;
  1230. PVOID BufferResource;
  1231. ULONG len = 0;
  1232. PWMI_LOGGER_CONTEXT LoggerContext;
  1233. PAGED_CODE();
  1234. LoggerContext = WmipIsLoggerOn(WmipKernelLogger);
  1235. if (LoggerContext == NULL) {
  1236. return;
  1237. }
  1238. try {
  1239. if( KeyName && KeyName->Buffer && KeyName->Length) {
  1240. len += KeyName->Length;
  1241. //
  1242. // make sure it is a valid unicode string
  1243. //
  1244. if( len & 1 ) {
  1245. len -= 1;
  1246. }
  1247. if ((len ==0 ) || (KeyName->Buffer[len/sizeof(WCHAR) -1] != 0) ) {
  1248. //
  1249. // make room for NULL terminator
  1250. //
  1251. len += sizeof(WCHAR);
  1252. }
  1253. } else {
  1254. len += sizeof(WCHAR);
  1255. }
  1256. }
  1257. except (EXCEPTION_EXECUTE_HANDLER) {
  1258. // KeyName buffer is from user. AV can happen.
  1259. return;
  1260. }
  1261. len += sizeof(PVOID) + sizeof(LONGLONG) + sizeof(ULONG);
  1262. #if defined(_WIN64)
  1263. len += sizeof(LONG64);
  1264. #else
  1265. len += sizeof(NTSTATUS);
  1266. #endif
  1267. Header = (PSYSTEM_TRACE_HEADER)
  1268. WmiReserveWithSystemHeader(
  1269. WmipKernelLogger,
  1270. len,
  1271. NULL,
  1272. &BufferResource);
  1273. if (Header == NULL) {
  1274. return;
  1275. }
  1276. Header->Packet.Group = (UCHAR) (EVENT_TRACE_GROUP_REGISTRY >> 8);
  1277. Header->Packet.Type = Type;
  1278. EventInfo = (PCHAR) ((PCHAR) Header + sizeof(SYSTEM_TRACE_HEADER));
  1279. #if defined(_WIN64)
  1280. *((LONG64 *)EventInfo) = (LONG64)Status;
  1281. EventInfo += sizeof(LONG64);
  1282. #else
  1283. *((NTSTATUS *)EventInfo) = Status;
  1284. EventInfo += sizeof(NTSTATUS);
  1285. #endif
  1286. *((PVOID *)EventInfo) = Kcb;
  1287. EventInfo += sizeof(PVOID);
  1288. *((LONGLONG *)EventInfo) = ElapsedTime;
  1289. EventInfo += sizeof(LONGLONG);
  1290. *((ULONG *)EventInfo) = Index;
  1291. EventInfo += sizeof(ULONG);
  1292. len -= (sizeof(HANDLE) + sizeof(LONGLONG) + sizeof(ULONG) );
  1293. #if defined(_WIN64)
  1294. len -= sizeof(LONG64);
  1295. #else
  1296. len -= sizeof(NTSTATUS);
  1297. #endif
  1298. try {
  1299. if( KeyName && KeyName->Buffer && KeyName->Length) {
  1300. RtlCopyMemory(EventInfo, KeyName->Buffer, len - sizeof(WCHAR));
  1301. }
  1302. }
  1303. except (EXCEPTION_EXECUTE_HANDLER) {
  1304. // Cleanup just in case
  1305. RtlZeroMemory(EventInfo, len - sizeof(WCHAR));
  1306. }
  1307. ((PWCHAR)EventInfo)[len/sizeof(WCHAR) -1] = UNICODE_NULL;
  1308. WmipReleaseTraceBuffer(BufferResource, LoggerContext);
  1309. }
  1310. VOID
  1311. FASTCALL
  1312. WmiTraceContextSwap (
  1313. IN PETHREAD OldEThread,
  1314. IN PETHREAD NewEThread )
  1315. /*++
  1316. Routine Description:
  1317. This routine is called to trace context swap
  1318. operations. It is called directly from the
  1319. context swap procedure while the context swap
  1320. lock is being held, so it is critical that this
  1321. routine not take any locks.
  1322. Assumptions:
  1323. - This routine will only be called from the ContextSwap routine
  1324. - This routine will always be called at IRQL >= DISPATCH_LEVEL
  1325. - This routine will only be called when the PPerfGlobalGroupMask
  1326. is not equal to null, and the context swap flag is set within
  1327. the structure to which PPerfGlobalGroupMask points to,
  1328. and the kernel's WMI_LOGGER_CONTEXT struct has been fully initialized.
  1329. - The Wmi kernel WMI_LOGGER_CONTEXT object, as well as all buffers
  1330. it allocates are allocated from nonpaged pool. All Wmi globals
  1331. that we access are also in nonpaged memory.
  1332. - This code has been locked into paged memory when the logger started
  1333. - The logger context reference count has been incremented via the
  1334. InterlockedIncrement() operation in WmipReferenceLogger(WmipKernelLogger)
  1335. by our start code.
  1336. Arguments:
  1337. OldThread - ptr to ETHREAD object of thread
  1338. being swapped out
  1339. NewThread - ptr to ETHREAD object of thread
  1340. being swapped in
  1341. Return Value:
  1342. None
  1343. --*/
  1344. {
  1345. UCHAR CurrentProcessor;
  1346. PWMI_BUFFER_HEADER Buffer;
  1347. PPERFINFO_TRACE_HEADER EventHeader;
  1348. SIZE_T EventSize;
  1349. PWMI_CONTEXTSWAP ContextSwapData;
  1350. //
  1351. // Figure out which processor we are running on
  1352. //
  1353. CurrentProcessor = (UCHAR)KeGetCurrentProcessorNumber();
  1354. //
  1355. // If we currently have no context swap buffer for this processor
  1356. // then we need to grab one from the ETW Free list.
  1357. //
  1358. Buffer = WmipContextSwapProcessorBuffers[CurrentProcessor];
  1359. if (Buffer == NULL) {
  1360. Buffer = WmipPopFreeContextSwapBuffer(
  1361. CurrentProcessor);
  1362. if( Buffer == NULL ) {
  1363. return;
  1364. }
  1365. //
  1366. // We have a legitimate buffer, so now we
  1367. // set it as this processor's current cxtswap buffer
  1368. //
  1369. WmipContextSwapProcessorBuffers[CurrentProcessor] = Buffer;
  1370. }
  1371. if (Buffer->Offset <= Buffer->CurrentOffset) {
  1372. //
  1373. // Due to an rare unfortunate timing issue with buffer recycle,
  1374. // buffer CurrentOffset is corrupt. We should not write over
  1375. // buffer boundary.
  1376. //
  1377. WmipPushDirtyContextSwapBuffer(CurrentProcessor, Buffer);
  1378. //
  1379. // Zero out the processor buffer pointer so that when we next come
  1380. // into the trace code, we know to grab another one.
  1381. //
  1382. WmipContextSwapProcessorBuffers[CurrentProcessor] = NULL;
  1383. return;
  1384. }
  1385. //
  1386. // Compute the pointers to our event structures within the buffer
  1387. // At this point, we will always have enough space in the buffer for
  1388. // this event. We check for a full buffer after we fill out the event
  1389. //
  1390. EventHeader = (PPERFINFO_TRACE_HEADER)( (SIZE_T)Buffer
  1391. + (SIZE_T)Buffer->CurrentOffset);
  1392. ContextSwapData = (PWMI_CONTEXTSWAP)( (SIZE_T)EventHeader
  1393. + (SIZE_T)FIELD_OFFSET(PERFINFO_TRACE_HEADER, Data ));
  1394. EventSize = sizeof(WMI_CONTEXTSWAP)
  1395. + FIELD_OFFSET(PERFINFO_TRACE_HEADER, Data);
  1396. //
  1397. // Fill out the event header
  1398. //
  1399. EventHeader->Marker = PERFINFO_TRACE_MARKER;
  1400. EventHeader->Packet.Size = (USHORT) EventSize;
  1401. EventHeader->Packet.HookId = PERFINFO_LOG_TYPE_CONTEXTSWAP;
  1402. PerfTimeStamp(EventHeader->SystemTime);
  1403. //
  1404. // Assert that the event size is at alligned correctly
  1405. //
  1406. ASSERT( EventSize % WMI_CTXSWAP_EVENTSIZE_ALIGNMENT == 0);
  1407. //
  1408. // Fill out the event data struct for context swap
  1409. //
  1410. ContextSwapData->NewThreadId = HandleToUlong(NewEThread->Cid.UniqueThread);
  1411. ContextSwapData->OldThreadId = HandleToUlong(OldEThread->Cid.UniqueThread);
  1412. ContextSwapData->NewThreadPriority = NewEThread->Tcb.Priority;
  1413. ContextSwapData->OldThreadPriority = OldEThread->Tcb.Priority;
  1414. ContextSwapData->NewThreadQuantum = NewEThread->Tcb.Quantum;
  1415. ContextSwapData->OldThreadQuantum = OldEThread->Tcb.Quantum;
  1416. ContextSwapData->OldThreadWaitReason= OldEThread->Tcb.WaitReason;
  1417. ContextSwapData->OldThreadWaitMode = OldEThread->Tcb.WaitMode;
  1418. ContextSwapData->OldThreadState = OldEThread->Tcb.State;
  1419. ContextSwapData->OldThreadIdealProcessor =
  1420. OldEThread->Tcb.IdealProcessor;
  1421. //
  1422. // Increment the offset. Don't need synchronization here because
  1423. // IRQL >= DISPATCH_LEVEL.
  1424. //
  1425. Buffer->CurrentOffset += (ULONG)EventSize;
  1426. //
  1427. // Check if the buffer is full by taking the difference between
  1428. // the buffer's maximum offset and the current offset.
  1429. //
  1430. if ((Buffer->Offset - Buffer->CurrentOffset) <= EventSize) {
  1431. //
  1432. // Push the full buffer onto the FlushList.
  1433. //
  1434. WmipPushDirtyContextSwapBuffer(CurrentProcessor, Buffer);
  1435. //
  1436. // Zero out the processor buffer pointer so that when we next come
  1437. // into the trace code, we know to grab another one.
  1438. //
  1439. WmipContextSwapProcessorBuffers[CurrentProcessor] = NULL;
  1440. }
  1441. return;
  1442. }
  1443. VOID
  1444. FASTCALL
  1445. WmiStartContextSwapTrace
  1446. (
  1447. )
  1448. /*++
  1449. Routine Description:
  1450. Allocates the memory to track the per-processor buffers
  1451. used by context swap tracing. "locks" the logger by incrementing
  1452. the logger context reference count by one.
  1453. Assumptions:
  1454. - This function will not run at DISPATCH or higher
  1455. - The kernel logger context mutex has been acquired before entering
  1456. this function.
  1457. Calling Functions:
  1458. - PerfInfoStartLog
  1459. Arguments:
  1460. None
  1461. Return Value:
  1462. None
  1463. --*/
  1464. {
  1465. //
  1466. // Only used in checked builds - asserts if this code is called with
  1467. // Irql > APC_LEVEL.
  1468. //
  1469. PAGED_CODE();
  1470. //
  1471. // Set the pointers to our buffers to NULL, indicating to the trace event
  1472. // code that a buffer needs to be acquired.
  1473. //
  1474. RtlZeroMemory(
  1475. WmipContextSwapProcessorBuffers,
  1476. sizeof(PWMI_BUFFER_HEADER)*MAXIMUM_PROCESSORS);
  1477. }
  1478. VOID
  1479. FASTCALL
  1480. WmiStopContextSwapTrace
  1481. (
  1482. )
  1483. /*++
  1484. Routine Description:
  1485. Forces a context swap on a processor by jumping onto it.
  1486. Once a context swap has occured on a processor after the context
  1487. swap tracing flag has been disabled, we are guaranteed that the
  1488. buffer associated with that processor is not in use. It is then
  1489. safe to place that buffer on the flush list.
  1490. Assumptions:
  1491. - This function will not run at DISPATCH
  1492. - The kernel logger context mutex was acquired before this function
  1493. was called.
  1494. Calling Functions:
  1495. -PerfInfoStopLog
  1496. Arguments:
  1497. None
  1498. Return Value:
  1499. None; if we fail here there's nothing we can do anyway.
  1500. --*/
  1501. {
  1502. PKTHREAD ThisThread;
  1503. KAFFINITY OriginalAffinity;
  1504. UCHAR i;
  1505. PWMI_LOGGER_CONTEXT LoggerContext;
  1506. //
  1507. // Only used in checked builds - asserts if this code is called with
  1508. // Irql > APC_LEVEL.
  1509. //
  1510. PAGED_CODE();
  1511. //
  1512. // Remember the original thread affinity
  1513. //
  1514. ThisThread = KeGetCurrentThread();
  1515. OriginalAffinity = ThisThread->Affinity;
  1516. //
  1517. // Get the kernel logger context- this should never fail.
  1518. // If we can't get the logger context, then we have nowhere
  1519. // to flush buffers and we might as well stop here.
  1520. //
  1521. LoggerContext = WmipLoggerContext[WmipKernelLogger];
  1522. if( !WmipIsValidLogger( LoggerContext ) ) {
  1523. return;
  1524. }
  1525. //
  1526. // Loop through all processors and place their buffers on the flush list
  1527. // This would probably break if the number of processors were decreased in
  1528. // the middle of the trace.
  1529. //
  1530. for(i=0; i<KeNumberProcessors; i++) {
  1531. //
  1532. // Set the hard processor affinity to 1 << i
  1533. // This effectively jumps onto the processor
  1534. //
  1535. KeSetSystemAffinityThread ( AFFINITY_MASK(i) );
  1536. //
  1537. // Check to make sure this processor even has a buffer,
  1538. // if it doesn't, then next loop
  1539. //
  1540. if(WmipContextSwapProcessorBuffers[i] == NULL) {
  1541. continue;
  1542. }
  1543. //
  1544. // Release the buffer to the flush list
  1545. //
  1546. WmipPushDirtyContextSwapBuffer(i, WmipContextSwapProcessorBuffers[i]);
  1547. WmipContextSwapProcessorBuffers[i] = NULL;
  1548. }
  1549. //
  1550. // Set our Affinity back to normal
  1551. //
  1552. KeSetSystemAffinityThread( OriginalAffinity );
  1553. KeRevertToUserAffinityThread();
  1554. return;
  1555. }
  1556. PWMI_LOGGER_CONTEXT
  1557. FASTCALL
  1558. WmipIsLoggerOn(
  1559. IN ULONG LoggerId
  1560. )
  1561. {
  1562. PWMI_LOGGER_CONTEXT LoggerContext;
  1563. if (LoggerId >= MAXLOGGERS) {
  1564. return NULL;
  1565. }
  1566. LoggerContext = WmipLoggerContext[LoggerId];
  1567. if (WmipIsValidLogger(LoggerContext)) {
  1568. return LoggerContext;
  1569. }
  1570. else {
  1571. return NULL;
  1572. }
  1573. }