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.

1792 lines
60 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 2000.
  5. //
  6. // File: wmiTrace.c
  7. //
  8. // Contents: windbg extension to dump WMI Trace Buffers
  9. //
  10. // Classes:
  11. //
  12. // Functions: help Standard KD Extension Function
  13. // strdump Dump the Logger Structure
  14. // logdump Dump the in-memory part of the TraceBuffers
  15. // logsave Save the in-memory part of the TraceBuffers
  16. // to a file.
  17. // wmiLogDump Callable procedure used when caller wishes
  18. // to replace the filter, sort, or output routines
  19. //
  20. // Coupling:
  21. //
  22. // Notes:
  23. //
  24. // History: 04-27-2000 glennp Created
  25. // 07-17-2000 glennp Added support for Stephen Hsiao's
  26. // Non-Blocking Buffers.
  27. // 12-13-2000 glennp Changed from typedefs to struct tags
  28. // per change in compiler behavior.
  29. //
  30. //----------------------------------------------------------------------------
  31. #include "kdExts.h"
  32. #define _WMI_SOURCE_
  33. #include <wmium.h>
  34. #include <ntwmi.h>
  35. #include <evntrace.h>
  36. #include <wmiumkm.h>
  37. #include <traceprt.h>
  38. #include "wmiTrace.h"
  39. #pragma hdrstop
  40. typedef ULONG64 TARGET_ADDRESS;
  41. typedef VOID (*WMITRACING_KD_LISTENTRY_PROC)
  42. ( PVOID Context
  43. , TARGET_ADDRESS Buffer
  44. , ULONG Length
  45. , ULONG CpuNo
  46. , ULONG Align
  47. , WMI_BUFFER_SOURCE Source
  48. );
  49. typedef struct _WMITRACING_BUFFER_SOURCES {
  50. ULONG FreeBuffers:1;
  51. ULONG FlushBuffers:1;
  52. ULONG ActiveBuffers:1;
  53. ULONG TransitionBuffer:1;
  54. ULONG PrintInformation:1;
  55. ULONG PrintProgressIndicator:1;
  56. } WMITRACING_BUFFER_SOURCES;
  57. struct sttSortControl
  58. {
  59. ULONG MaxEntries;
  60. ULONG CurEntries;
  61. WMITRACING_KD_SORTENTRY *pstSortEntries;
  62. };
  63. struct sttTraceContext
  64. {
  65. struct sttSortControl *pstSortControl;
  66. PVOID UserContext;
  67. ULONG BufferSize;
  68. ULONG Ordinal;
  69. WMITRACING_KD_FILTER Filter;
  70. };
  71. struct sttSaveContext
  72. {
  73. FILE *pfSaveFile;
  74. };
  75. extern DBGKD_GET_VERSION64 KernelVersionData;
  76. TARGET_ADDRESS TransitionBuffer;
  77. //+---------------------------------------------------------------------------
  78. //
  79. // Function: void printUnicodeFromAddress
  80. //
  81. // Synopsis: Prints a UNICODE string given the address of the UNICODE_STRING
  82. //
  83. // Arguments: ul64Address The Address of the UNICODE_STRING structure
  84. //
  85. // Returns: <VOID>
  86. //
  87. // History: 04-05-2000 glennp Created
  88. //
  89. // Notes:
  90. //
  91. //----------------------------------------------------------------------------
  92. void printUnicodeFromAddress (TARGET_ADDRESS ul64Address)
  93. {
  94. TARGET_ADDRESS ul64TarBuffer;
  95. ULONG bufferOffset;
  96. ULONG lengthRead;
  97. ULONG ulInfo;
  98. USHORT usLength;
  99. PWCHAR buffer;
  100. ul64TarBuffer = 0;
  101. bufferOffset = 0;
  102. usLength = 0;
  103. buffer = NULL;
  104. GetFieldOffset ("UNICODE_STRING", "Buffer", &bufferOffset);
  105. ReadPtr (ul64Address + bufferOffset, &ul64TarBuffer);
  106. GetFieldValue (ul64Address, "UNICODE_STRING", "Length", usLength);
  107. buffer = LocalAlloc (LPTR, usLength + sizeof (UNICODE_NULL));
  108. if (buffer == NULL) {
  109. dprintf ("<Failed to Allocate Unicode String Buffer>");
  110. return;
  111. }
  112. if (usLength > 0) {
  113. lengthRead = 0;
  114. ulInfo = ReadMemory (ul64TarBuffer, buffer, usLength, &lengthRead);
  115. if ((!ulInfo) || (lengthRead != usLength)) {
  116. dprintf ("<Failed to Read Entire Unicode String>");
  117. }
  118. }
  119. buffer [usLength / 2] = 0;
  120. dprintf ("%ws", buffer);
  121. LocalFree(buffer);
  122. return;
  123. }
  124. //+---------------------------------------------------------------------------
  125. //
  126. // Function: ULONG lengthUnicodeFromAddress
  127. //
  128. // Synopsis: Get the Length (in bytes) of a UNICODE_STRING (NULL not included)
  129. //
  130. // Arguments: ul64Address The Address of the UNICODE_STRING structure
  131. //
  132. // Returns: Length of String in Bytes
  133. //
  134. // History: 03-27-2000 glennp Created
  135. //
  136. // Notes:
  137. //
  138. //----------------------------------------------------------------------------
  139. ULONG lengthUnicodeFromAddress (TARGET_ADDRESS ul64Address)
  140. {
  141. USHORT usLength;
  142. usLength = 0;
  143. GetFieldValue (ul64Address, "UNICODE_STRING", "Length", usLength);
  144. return ((ULONG) (usLength));
  145. }
  146. //+---------------------------------------------------------------------------
  147. //
  148. // Function: void printUnicodeFromStruct
  149. //
  150. // Synopsis: Prints a UNICODE string from an element in a structure
  151. //
  152. // Arguments: Address The Address of the structure containing the US
  153. // Type The Type of the structure containing the US
  154. // Field The name of the field in the structure
  155. // This must be a UNICODE_STRING substructure
  156. //
  157. // Returns: <VOID>
  158. //
  159. // History: 04-05-2000 glennp Created
  160. //
  161. // Notes:
  162. //
  163. //----------------------------------------------------------------------------
  164. void printUnicodeFromStruct (TARGET_ADDRESS Address, PCHAR Type, PCHAR Field)
  165. {
  166. ULONG ulUnicodeOffset;
  167. GetFieldOffset (Type, Field, &ulUnicodeOffset);
  168. printUnicodeFromAddress (Address + ulUnicodeOffset);
  169. return;
  170. }
  171. //+---------------------------------------------------------------------------
  172. //
  173. // Function: ULONG GetWmiTraceAlignment
  174. //
  175. // Synopsis: Determines the Alignment modulus for events on the target
  176. //
  177. // Arguments: <NONE>
  178. //
  179. // Returns: The Alignment (normally 8 bytes)
  180. //
  181. // History: 04-05-2000 glennp Created
  182. //
  183. // Notes:
  184. //
  185. //----------------------------------------------------------------------------
  186. ULONG GetWmiTraceAlignment (void)
  187. {
  188. ULONG ulInfo;
  189. ULONG ulBytesRead;
  190. UCHAR alignment;
  191. TARGET_ADDRESS tarAddress;
  192. alignment = 8; // Set Default
  193. tarAddress = GetExpression ("NT!WmiTraceAlignment");
  194. ulInfo = ReadMemory (tarAddress, &alignment, sizeof (UCHAR), &ulBytesRead);
  195. if ((!ulInfo) || (ulBytesRead != sizeof (UCHAR))) {
  196. dprintf ("Failed to Read Alignment.\n");
  197. }
  198. return ((ULONG) alignment);
  199. }
  200. //+---------------------------------------------------------------------------
  201. //
  202. // Function: TARGET_ADDRESS FindLoggerContextArray
  203. //
  204. // Synopsis: Determines the location and size of the LoggerContext Array
  205. //
  206. // Arguments: -> ElementCount The number of elements in the array put here
  207. //
  208. // Returns: Target Address of the LoggerContext Array
  209. //
  210. // History: 04-05-2000 glennp Created
  211. //
  212. // Notes: Returns 0 on error
  213. //
  214. //----------------------------------------------------------------------------
  215. TARGET_ADDRESS FindLoggerContextArray (PULONG ElementCount)
  216. {
  217. TARGET_ADDRESS address;
  218. ULONG pointerSize;
  219. ULONG arraySize;
  220. address = 0;
  221. pointerSize = GetTypeSize ("PVOID");
  222. if ((arraySize = GetTypeSize ("NT!WmipLoggerContext") / pointerSize) != 0) {
  223. // Post Windows 2000 Version
  224. address = GetExpression ("NT!WmipLoggerContext");
  225. } else {
  226. // Windows 2000 and Before
  227. ULONG ulOffset;
  228. address = GetExpression ("NT!WmipServiceDeviceObject");
  229. ReadPtr (address, &address);
  230. GetFieldOffset ("DEVICE_OBJECT", "DeviceExtension", &ulOffset);
  231. ReadPtr (address + ulOffset, &address);
  232. GetFieldOffset ("WMISERVDEVEXT", "LoggerContextTable", &ulOffset);
  233. // ulOffset = 0x50;
  234. address += ulOffset;
  235. arraySize = GetTypeSize ("WMISERVDEVEXT.LoggerContextTable") / pointerSize;
  236. // arraySize = 32;
  237. }
  238. *ElementCount = arraySize;
  239. return (address);
  240. }
  241. //+---------------------------------------------------------------------------
  242. //
  243. // Function: TARGET_ADDRESS FindLoggerContext
  244. //
  245. // Synopsis: Finds the Address of a specific LoggerContext
  246. //
  247. // Arguments: ulLoggerId Ordinal of the specific LoggerContext
  248. //
  249. // Returns: Target Address of the LoggerContext
  250. //
  251. // History: 04-05-2000 glennp Created
  252. //
  253. // Notes: Returns 0 on error
  254. //
  255. //----------------------------------------------------------------------------
  256. TARGET_ADDRESS FindLoggerContext (ULONG ulLoggerId)
  257. {
  258. TARGET_ADDRESS tarAddress;
  259. ULONG ulMaxLoggerId;
  260. tarAddress = FindLoggerContextArray (&ulMaxLoggerId);
  261. if (tarAddress == 0) {
  262. dprintf (" Unable to Access Logger Context Array\n");
  263. } else {
  264. if (ulLoggerId >= ulMaxLoggerId) {
  265. dprintf (" Logger Id TOO LARGE\n");
  266. } else {
  267. // tarAddress += GetTypeSize ("PWMI_LOGGER_CONTEXT") * ulLoggerId; //BUGBUG
  268. tarAddress += GetTypeSize ("PVOID") * ulLoggerId;
  269. ReadPointer (tarAddress, &tarAddress);
  270. if (tarAddress == 0) {
  271. dprintf (" LOGGER ID %2d NOT RUNNING PRESENTLY\n", ulLoggerId);
  272. }
  273. }
  274. }
  275. return (tarAddress);
  276. }
  277. //+---------------------------------------------------------------------------
  278. //
  279. // Function: wmiDefaultFilter
  280. //
  281. // Synopsis: Filter procedure for wmiTracing. Returns Key
  282. //
  283. // Arguments: Context Arbitrary context: not used
  284. // pstEvent -> to EventTrace
  285. //
  286. // Returns: Key
  287. //
  288. // History: 04-05-2000 glennp Created
  289. //
  290. // Notes:
  291. //
  292. //----------------------------------------------------------------------------
  293. ULONGLONG __cdecl wmiDefaultFilter (
  294. PVOID Context,
  295. const PEVENT_TRACE pstEvent
  296. )
  297. {
  298. union {
  299. LARGE_INTEGER TimeStamp;
  300. ULONGLONG Key;
  301. } Union;
  302. Union.TimeStamp = pstEvent->Header.TimeStamp;
  303. if (Union.Key == 0) Union.Key = 1;
  304. return (Union.Key);
  305. }
  306. //+---------------------------------------------------------------------------
  307. //
  308. // Function: wmiDefaultCompare
  309. //
  310. // Synopsis: Performs comparision of three keys
  311. //
  312. // Arguments: SortElement1 -> to "Left" sort element to compare
  313. // SortElement2 -> to "Right" sort element to compare
  314. //
  315. // Returns: -3,-2,-1, 0, +1,+2,+3 for LessThan, Equal, GreaterThan (Left X Right)
  316. //
  317. // History: 04-05-2000 glennp Created
  318. //
  319. // Notes: The first key, "SequenceNo", is compared in a manor that allows
  320. // wrapping around the 32 bit limit.
  321. // The last key, "Ordinal", cannot have equal values and the code
  322. // takes advantage of that fact. This implies that 0 can never be returned.
  323. //
  324. //----------------------------------------------------------------------------
  325. int __cdecl wmiDefaultCompare (
  326. const WMITRACING_KD_SORTENTRY *SortElementL,
  327. const WMITRACING_KD_SORTENTRY *SortElementR
  328. )
  329. {
  330. int iResult;
  331. ULONG SequenceNoL;
  332. ULONG SequenceNoR;
  333. SequenceNoL = SortElementL->SequenceNo;
  334. SequenceNoR = SortElementR->SequenceNo;
  335. if (SequenceNoL == SequenceNoR) {
  336. if (SortElementL->Keyll == SortElementR->Keyll) {
  337. iResult = (SortElementL->Ordinal < SortElementR->Ordinal) ? -1 : +1;
  338. } else {
  339. iResult = (SortElementL->Keyll < SortElementR->Keyll) ? -2 : +2;
  340. }
  341. } else {
  342. iResult = ((SequenceNoL - SequenceNoR) > 0x80000000) ? -3 : +3; // See Notes
  343. }
  344. return (iResult);
  345. }
  346. //+---------------------------------------------------------------------------
  347. //
  348. // Function: wmiDefaultOutput
  349. //
  350. // Synopsis: Output procedure for wmiTracing. Performs simple dprintf
  351. //
  352. // Arguments: Context Arbitrary context: point to head of MOF list
  353. // SortElement -> sort element describing this event. Not used.
  354. // pstEvent -> to EventTrace
  355. //
  356. // Returns: <void>
  357. //
  358. // History: 04-05-2000 glennp Created
  359. //
  360. // Notes:
  361. //
  362. //----------------------------------------------------------------------------
  363. void __cdecl wmiDefaultOutput (
  364. PVOID UserContext,
  365. PLIST_ENTRY GuidListHeadPtr,
  366. const WMITRACING_KD_SORTENTRY *SortEntry,
  367. const PEVENT_TRACE pstHeader
  368. )
  369. {
  370. WCHAR wcaOutputLine[4096];
  371. wcaOutputLine[0] = 0;
  372. FormatTraceEvent (GuidListHeadPtr, (PEVENT_TRACE) pstHeader,
  373. (TCHAR *) wcaOutputLine, sizeof (wcaOutputLine),
  374. (TCHAR *) NULL);
  375. dprintf ("%s\n", wcaOutputLine);
  376. return;
  377. }
  378. //+---------------------------------------------------------------------------
  379. //
  380. // Function: wmiKdProcessLinkList
  381. //
  382. // Synopsis: Calls supplied Procedure for each element in a linked list
  383. //
  384. // Arguments: TarLinklistHeadAddress Target Address of Linklist Head
  385. // Procedure Procedure to call for each Buffer
  386. // Context Procedure Context (passthrough)
  387. // Length Size of the Buffer
  388. // Alignment Entry alignment in bytes
  389. // Source Enum specifying type of buffer
  390. // Offset Offset of LL entry in Buffer
  391. // Print Flag passed to Procedure
  392. //
  393. // Returns: Count of Buffers Processed
  394. //
  395. // History: 04-05-2000 glennp Created
  396. //
  397. // Notes:
  398. //
  399. //----------------------------------------------------------------------------
  400. ULONG wmiKdProcessLinkList (
  401. TARGET_ADDRESS TarLinklistHeadAddress,
  402. WMITRACING_KD_LISTENTRY_PROC Procedure,
  403. PVOID Context,
  404. ULONG Length,
  405. ULONG Alignment,
  406. WMI_BUFFER_SOURCE Source,
  407. ULONG Offset,
  408. ULONG Print
  409. )
  410. {
  411. ULONG ulBufferCount;
  412. TARGET_ADDRESS tarLinklistEntryAddress;
  413. ulBufferCount = 0;
  414. tarLinklistEntryAddress = TarLinklistHeadAddress;
  415. while (ReadPtr (tarLinklistEntryAddress, &tarLinklistEntryAddress), // NOTE COMMA!
  416. tarLinklistEntryAddress != TarLinklistHeadAddress) {
  417. if (CheckControlC()) break;
  418. ++ulBufferCount;
  419. if (Print) { dprintf ("%4d\b\b\b\b", ulBufferCount); }
  420. Procedure (Context, tarLinklistEntryAddress - Offset, Length, ~0, Alignment, Source);
  421. }
  422. return ulBufferCount;
  423. }
  424. //+---------------------------------------------------------------------------
  425. //
  426. // Function: VOID wmiDumpProc
  427. //
  428. // Synopsis: Procedure passed to wmiKdProcessBuffers() when dumping the
  429. // Buffers to the screen. Performs Buffer Header fixup and
  430. // then records sort keys for those entries that are selected.
  431. //
  432. // Arguments: Context -> to struct sttTraceContext. Used for 'static' memory
  433. // Buffer Target Address of WMI Event buffer to analyze
  434. // Length Length of the buffer (previous parameter)
  435. // Alignment Alignment used by WMI on target machine
  436. // Source Enum of: free, flush, transition, current buffer source
  437. //
  438. // Returns: <VOID>
  439. //
  440. // History: 04-05-2000 glennp Created
  441. //
  442. // Notes:
  443. //
  444. //----------------------------------------------------------------------------
  445. VOID wmiDumpProc
  446. ( PVOID Context
  447. , TARGET_ADDRESS Buffer
  448. , ULONG Length
  449. , ULONG CpuNo
  450. , ULONG Alignment
  451. , WMI_BUFFER_SOURCE Source
  452. )
  453. {
  454. ULONG size;
  455. ULONG offset;
  456. ULONG ulInfo;
  457. ULONG ulLengthRead;
  458. PUCHAR pBuffer;
  459. WMI_HEADER_TYPE headerType;
  460. WMIBUFFERINFO stBufferInfo;
  461. struct sttTraceContext *pstContext;
  462. // Cast Context
  463. pstContext = (struct sttTraceContext *) Context;
  464. // Allocate Buffer
  465. pBuffer = LocalAlloc (LPTR, Length);
  466. if (pBuffer == NULL) {
  467. dprintf ("Failed to Allocate Buffer.\n");
  468. return;
  469. }
  470. // Copy Buffer from Target machine
  471. ulLengthRead = 0;
  472. ulInfo = ReadMemory (Buffer, pBuffer, Length, &ulLengthRead);
  473. if ((!ulInfo) || (ulLengthRead != Length)) {
  474. dprintf ("Failed to Read (Entire?) Buffer.\n");
  475. }
  476. // Get Initial Offset and Fixup Header
  477. memset (&stBufferInfo, 0, sizeof (stBufferInfo));
  478. stBufferInfo.BufferSource = Source;
  479. stBufferInfo.Buffer = pBuffer;
  480. stBufferInfo.BufferSize = Length;
  481. stBufferInfo.Alignment = Alignment;
  482. stBufferInfo.ProcessorNumber = CpuNo;
  483. offset = WmiGetFirstTraceOffset (&stBufferInfo);
  484. // Inspect Each Event
  485. while ((headerType = WmiGetTraceHeader (pBuffer, offset, &size)) != WMIHT_NONE) {
  486. ULONG ulInfo;
  487. ULONGLONG ullKey;
  488. union {
  489. EVENT_TRACE stEvent;
  490. CHAR caEvent[4096];
  491. } u;
  492. if (CheckControlC()) break;
  493. // Get a consistant header
  494. ulInfo = WmiParseTraceEvent (pBuffer, offset, headerType, &u, sizeof (u));
  495. // Filter and maybe Add to Sort Q
  496. if ((ullKey = pstContext->Filter (pstContext, &u.stEvent)) != 0) {
  497. ULONG CurIndex;
  498. PWMI_CLIENT_CONTEXT pstClientContext;
  499. struct sttSortControl *pstSortControl;
  500. PWMITRACING_KD_SORTENTRY pstSortEntry;
  501. pstClientContext = (PWMI_CLIENT_CONTEXT) &u.stEvent.Header.ClientContext;
  502. pstSortControl = pstContext->pstSortControl;
  503. CurIndex = pstSortControl->CurEntries;
  504. if (CurIndex >= pstSortControl->MaxEntries) {
  505. pstSortControl->MaxEntries = pstSortControl->MaxEntries * 2 + 64;
  506. pstSortControl->pstSortEntries =
  507. realloc (pstSortControl->pstSortEntries,
  508. sizeof (WMITRACING_KD_SORTENTRY) * (pstSortControl->MaxEntries));
  509. if (pstSortControl->pstSortEntries == NULL) {
  510. dprintf ("Memory Allocation Failure\n");
  511. return;
  512. }
  513. }
  514. pstSortEntry = &pstSortControl->pstSortEntries[CurIndex];
  515. memset (pstSortEntry, 0, sizeof (*pstSortEntry));
  516. pstSortEntry->Address = Buffer;
  517. pstSortEntry->Keyll = ullKey;
  518. { //BUGBUG: This code should be replaced after Ian/Melur supply a way to access SequenceNo
  519. PULONG pulEntry;
  520. pulEntry = (PULONG) &pBuffer[offset];
  521. if (((pulEntry[0] & 0xFF000000) == 0x90000000) &&
  522. ( pulEntry[1] & 0x00010000)) {
  523. pstSortEntry->SequenceNo = pulEntry[2];
  524. } else {
  525. pstSortEntry->SequenceNo = 0;
  526. }
  527. }
  528. pstSortEntry->Ordinal = pstContext->Ordinal++;
  529. pstSortEntry->Offset = offset;
  530. pstSortEntry->Length = size;
  531. pstSortEntry->BufferSource = Source;
  532. pstSortEntry->HeaderType = headerType;
  533. pstSortEntry->CpuNo = (USHORT) CpuNo;
  534. pstSortControl->CurEntries++;
  535. } // If passes Filtering
  536. size = ((size + (Alignment-1)) / Alignment) * Alignment; //BUGBUG: Need fix in GetTraceHeader or WmiFlush. Then remove this line.
  537. offset += size; // Move to next entry.
  538. }
  539. LocalFree (pBuffer);
  540. return;
  541. }
  542. //+---------------------------------------------------------------------------
  543. //
  544. // Function: ULONG wmiKdWriteFileHeader
  545. //
  546. // Synopsis: Write the file header when performing a Save command.
  547. //
  548. // Arguments: SaveFile Handle to a file where we will write the header
  549. // LoggerId Ordinal of the Stream we are writing the header for
  550. // TarLoggerContext TargetAddress of the LoggerContext
  551. //
  552. // Returns: <VOID>
  553. //
  554. // History: 04-05-2000 glennp Created
  555. //
  556. // Notes: This code should really be in wmi somewhere. It's here due to
  557. // the difficulty of creating a simply parameterized procedure.
  558. //
  559. //----------------------------------------------------------------------------
  560. ULONG
  561. wmiKdWriteFileHeader
  562. ( FILE *SaveFile
  563. , ULONG LoggerId
  564. , TARGET_ADDRESS TarLoggerContext
  565. )
  566. {
  567. ULONG ulInfo;
  568. ULONG ulBytesRead;
  569. ULONG ulAlignment;
  570. ULONG ulBufferSize;
  571. ULONG ulBufferCount;
  572. ULONG ulPointerSize;
  573. ULONG ulHeaderWritten;
  574. ULONG ulInstanceGuidOffset;
  575. UCHAR MajorVersion;
  576. UCHAR MinorVersion;
  577. PROCESSORINFO ProcessorInfo;
  578. PCHAR pcEnd;
  579. struct sttFileHeader {
  580. WMI_BUFFER_HEADER Buffer;
  581. SYSTEM_TRACE_HEADER Event;
  582. TRACE_LOGFILE_HEADER Header;
  583. WCHAR LogName[256]; //BUGBUG: Size??
  584. WCHAR FileName[256]; //BUGBUG: Size??
  585. } stFileHeader;
  586. ZeroMemory (&stFileHeader, sizeof (stFileHeader));
  587. ulAlignment = GetWmiTraceAlignment ();
  588. ulPointerSize = GetTypeSize ("PVOID");
  589. GetFieldOffset ("_WMI_LOGGER_CONTEXT", "InstanceGuid", &ulInstanceGuidOffset);
  590. // Get ProcessorInfo and Kernel-User Shared Data
  591. Ioctl (IG_KD_CONTEXT, &ProcessorInfo, sizeof (ProcessorInfo));
  592. // Get Version Info
  593. if (!HaveDebuggerData ()) {
  594. dprintf ("No Version Information Available.");
  595. MajorVersion = MinorVersion = 0;
  596. } else {
  597. MajorVersion = (UCHAR) KernelVersionPacket.MajorVersion;
  598. MinorVersion = (UCHAR) KernelVersionPacket.MinorVersion;
  599. }
  600. // Get Infomation from LoggerContext on Target
  601. InitTypeRead (TarLoggerContext, _WMI_LOGGER_CONTEXT);
  602. ulBufferSize = (ULONG) ReadField (BufferSize);
  603. ulBufferCount = (ULONG) ReadField (NumberOfBuffers);
  604. stFileHeader.Buffer.Wnode.BufferSize = ulBufferSize;
  605. stFileHeader.Buffer.ClientContext.LoggerId =
  606. (USHORT) ((LoggerId) ? LoggerId : KERNEL_LOGGER_ID);
  607. stFileHeader.Buffer.ClientContext.Alignment = (UCHAR) ulAlignment;
  608. ulInfo = ReadMemory (TarLoggerContext + ulInstanceGuidOffset,
  609. &stFileHeader.Buffer.Wnode.Guid,
  610. sizeof (stFileHeader.Buffer.Wnode.Guid),
  611. &ulBytesRead);
  612. if ((!ulInfo) || (ulBytesRead != sizeof (stFileHeader.Buffer.Wnode.Guid))) {
  613. dprintf ("Unable to Read Wnode.Guid\n");
  614. }
  615. stFileHeader.Buffer.Wnode.Flags = WNODE_FLAG_TRACED_GUID;
  616. ulInfo = ReadMemory (TarLoggerContext + ulInstanceGuidOffset,
  617. &stFileHeader.Buffer.InstanceGuid,
  618. sizeof (stFileHeader.Buffer.InstanceGuid),
  619. &ulBytesRead);
  620. if ((!ulInfo) || (ulBytesRead != sizeof (stFileHeader.Buffer.InstanceGuid))) {
  621. dprintf ("Unable to Read InstanceGuid\n");
  622. }
  623. // Single Event (File Header)
  624. stFileHeader.Event.Marker = TRACE_HEADER_FLAG | TRACE_HEADER_EVENT_TRACE |
  625. ((ulPointerSize > 4) ? (TRACE_HEADER_TYPE_SYSTEM64 << 16)
  626. : (TRACE_HEADER_TYPE_SYSTEM32 << 16));
  627. stFileHeader.Event.Packet.Group = (UCHAR) EVENT_TRACE_GROUP_HEADER >> 8;
  628. stFileHeader.Event.Packet.Type = EVENT_TRACE_TYPE_INFO;
  629. stFileHeader.Header.StartTime.QuadPart = ReadField (StartTime);
  630. stFileHeader.Header.BufferSize = ulBufferSize;
  631. stFileHeader.Header.VersionDetail.MajorVersion = MajorVersion;
  632. stFileHeader.Header.VersionDetail.MinorVersion = MinorVersion;
  633. //
  634. // The following #if 0's show fields in the header difficult to access from the debugger.
  635. //
  636. #if 0
  637. stFileHeader.Header.VersionDetail.SubVersion = TRACE_VERSION_MAJOR;
  638. stFileHeader.Header.VersionDetail.SubMinorVersion = TRACE_VERSION_MINOR;
  639. stFileHeader.Header.ProviderVersion = NtBuildNumber;
  640. #endif
  641. stFileHeader.Header.StartBuffers = 1;
  642. #if 0
  643. stFileHeader.Header.BootTime = KeBootTime;
  644. stFileHeader.Header.LogFileMode = LocLoggerContext.LogFileMode &
  645. (~(EVENT_TRACE_REAL_TIME_MODE | EVENT_TRACE_FILE_MODE_CIRCULAR));
  646. #endif
  647. stFileHeader.Header.NumberOfProcessors = ProcessorInfo.NumberProcessors;
  648. stFileHeader.Header.MaximumFileSize = (ULONG) ReadField (MaximumFileSize);
  649. #if 0
  650. KeQueryPerformanceCounter (&stFileHeader.Header.PerfFreq);
  651. if (WmiUsePerfClock) {
  652. stFileHeader.Header.ReservedFlags = 1;
  653. }
  654. stFileHeader.Header.TimerResolution = KeMaximumIncrement; // DO NOT CHANGE KDDEBUGGER_DATA32!!
  655. #endif
  656. #if 0
  657. stFileHeader.Header.LoggerName = (PWCHAR) ( ( (PUCHAR) ( &stFileHeader.Header ) ) +
  658. sizeof(TRACE_LOGFILE_HEADER) );
  659. stFileHeader.Header.LogFileName = (PWCHAR) ( (PUCHAR)stFileHeader.Header.LoggerName +
  660. LocLoggerContext.LoggerName.Length +
  661. sizeof(UNICODE_NULL));
  662. if (!ReadTargetMemory (LocLoggerContext.LoggerName.Buffer,
  663. stFileHeader.Header.LoggerName,
  664. LocLoggerContext.LoggerName.Length + sizeof(UNICODE_NULL)) ) {
  665. dprintf ("Can't access LoggerName (LoggerContext.LoggerName.Buffer) memory.\n");
  666. }
  667. MultiByteToWideChar (
  668. CP_OEMCP, 0,
  669. pszSaveFileName, -1,
  670. stFileHeader.Header.LogFileName, countof (stFileHeader.FileName));
  671. #if 0
  672. RtlQueryTimeZoneInformation(&stFileHeader.Header.TimeZone);
  673. stFileHeader.Header.EndTime;
  674. #endif
  675. #endif
  676. stFileHeader.Header.PointerSize = ulPointerSize;
  677. pcEnd = (PCHAR) &stFileHeader.LogName; //BUGBUG: Use Calculation Just Below
  678. #if 0
  679. pcEnd = ((PCHAR) stFileHeader.Header.LogFileName) +
  680. ((strlen (pszSaveFileName) + 1) * sizeof (WCHAR));
  681. stFileHeader.Buffer.Offset = (ULONG) (pcEnd - ((PCHAR) &stFileHeader));
  682. #endif
  683. stFileHeader.Event.Packet.Size = (USHORT) (pcEnd - ((PCHAR) &stFileHeader.Event));
  684. //
  685. // Fixup Lengths; Write out Header, 0xFF to length of buffer
  686. //
  687. ulHeaderWritten = (ULONG) (pcEnd - ((PCHAR) &stFileHeader));
  688. stFileHeader.Buffer.Offset = ulHeaderWritten;
  689. stFileHeader.Buffer.SavedOffset = ulHeaderWritten;
  690. stFileHeader.Buffer.CurrentOffset = ulHeaderWritten;
  691. fwrite (&stFileHeader, ulHeaderWritten, 1, SaveFile);
  692. while (ulHeaderWritten < ulBufferSize) {
  693. ULONG ulAllOnes;
  694. ULONG ulByteCount;
  695. ulAllOnes = ~((ULONG) 0);
  696. ulByteCount = ulBufferSize - ulHeaderWritten;
  697. if (ulByteCount > sizeof (ulAllOnes)) ulByteCount = sizeof (ulAllOnes);
  698. fwrite (&ulAllOnes, ulByteCount, 1, SaveFile);
  699. ulHeaderWritten += sizeof (ulAllOnes);
  700. }
  701. return (0);
  702. }
  703. //+---------------------------------------------------------------------------
  704. //
  705. // Function: VOID wmiSaveProc
  706. //
  707. // Synopsis: Procedure passed to wmiKdProcessBuffers() when saving the
  708. // Buffers to a file for later processing. Performs buffer
  709. // Header fixup and then writes the buffer to the file.
  710. //
  711. // Arguments: Context -> to struct sttSaveContext. Used for 'static' memory
  712. // Buffer Target Address of WMI Event buffer to save
  713. // Length Length of the buffer (previous parameter)
  714. // Alignment Alignment used by WMI on target machine
  715. // Source Enum of: free, flush, transition, current: buffer source
  716. //
  717. // Returns: <VOID>
  718. //
  719. // History: 04-05-2000 glennp Created
  720. //
  721. // Notes:
  722. //
  723. //----------------------------------------------------------------------------
  724. VOID wmiSaveProc
  725. ( PVOID Context
  726. , TARGET_ADDRESS Buffer
  727. , ULONG Length
  728. , ULONG CpuNo
  729. , ULONG Alignment
  730. , WMI_BUFFER_SOURCE Source
  731. )
  732. {
  733. ULONG ulInfo;
  734. ULONG ulLengthRead;
  735. PCHAR pBuffer;
  736. struct sttSaveContext *pstContext;
  737. WMIBUFFERINFO stBufferInfo;
  738. pstContext = (struct sttSaveContext *) Context;
  739. // Allocate Buffer
  740. pBuffer = LocalAlloc (LPTR, Length);
  741. if (pBuffer == NULL) {
  742. dprintf ("Failed to Allocate Buffer.\n");
  743. return;
  744. }
  745. // Read Buffer
  746. ulLengthRead = 0;
  747. ulInfo = ReadMemory (Buffer, pBuffer, Length, &ulLengthRead);
  748. if ((!ulInfo) || (ulLengthRead != Length)) {
  749. dprintf ("Failed to Read (Entire?) Buffer.\n");
  750. }
  751. // Fixup Buffer Header
  752. memset (&stBufferInfo, 0, sizeof (stBufferInfo));
  753. stBufferInfo.BufferSource = Source;
  754. stBufferInfo.Buffer = pBuffer;
  755. stBufferInfo.BufferSize = Length;
  756. stBufferInfo.ProcessorNumber = CpuNo;
  757. stBufferInfo.Alignment = Alignment;
  758. WmiGetFirstTraceOffset (&stBufferInfo);
  759. // Write to Log File
  760. ulInfo = fwrite (pBuffer, 1, Length, pstContext->pfSaveFile);
  761. if (ulInfo != Length) {
  762. dprintf ("Failed to Write Buffer.\n");
  763. }
  764. // Free Buffer, Return
  765. LocalFree (pBuffer);
  766. return;
  767. }
  768. //+---------------------------------------------------------------------------
  769. //
  770. // Function: ULONG wmiKdProcessNonblockingBuffers
  771. //
  772. // Synopsis: Calls Caller-Supplied Procedure for each Buffer in Locations/
  773. // Lists as specified by 'Sources'. Walks lists, Enumerates
  774. // CPU's buffers, and handles 'Transition Buffer' logic.
  775. //
  776. // Arguments: LoggerId
  777. // LoggerContext
  778. // Procedure
  779. // Context
  780. // Sources
  781. //
  782. // Returns: ULONG: Number of Buffers Processed
  783. //
  784. // History: 04-05-2000 glennp Created
  785. //
  786. // Notes: Sources also controls informational printing
  787. //
  788. //----------------------------------------------------------------------------
  789. ULONG
  790. wmiKdProcessNonblockingBuffers(
  791. ULONG LoggerId,
  792. TARGET_ADDRESS LoggerContext,
  793. WMITRACING_KD_LISTENTRY_PROC Procedure,
  794. PVOID Context,
  795. WMITRACING_BUFFER_SOURCES Sources
  796. )
  797. {
  798. TARGET_ADDRESS tarAddress;
  799. TARGET_ADDRESS tarBufferListPointer;
  800. ULONG pointerSize;
  801. PROCESSORINFO ProcessorInfo;
  802. ULONG ulOrdinal;
  803. ULONG ulAlignment;
  804. ULONG ulBufferSize;
  805. ULONG ulLoopCount;
  806. ULONG ulBufferCount;
  807. ULONG ulBufferNumber;
  808. ULONG tarBufferListOffset;
  809. // Get Pointer to Context Structure
  810. tarAddress = LoggerContext;
  811. if (tarAddress == 0) return (0);
  812. // Initialize Locals
  813. ulBufferNumber = 0;
  814. ulBufferCount = 0;
  815. ulLoopCount = 0;
  816. // Get Sizes, Offsets, Alignments from Target
  817. pointerSize = GetTypeSize ("PVOID");
  818. ulAlignment = GetWmiTraceAlignment ();
  819. GetFieldOffset ("_WMI_BUFFER_HEADER", "GlobalEntry", &tarBufferListOffset);
  820. // Optionally Print LoggerId, Context Address, Logger name
  821. if (Sources.PrintInformation) {
  822. dprintf (" Logger Id %2d @ 0x%P Named '", LoggerId, tarAddress);
  823. printUnicodeFromStruct (tarAddress, "_WMI_LOGGER_CONTEXT", "LoggerName");
  824. dprintf ("'\n");
  825. }
  826. // Setup ReadField's Context, Find Buffer Size
  827. InitTypeRead (tarAddress, _WMI_LOGGER_CONTEXT);
  828. ulBufferSize = (ULONG) ReadField (BufferSize);
  829. // Optionally Print a few interesting numbers
  830. if (Sources.PrintInformation) {
  831. dprintf (" Alignment = %ld\n", ulAlignment);
  832. dprintf (" BufferSize = %ld\n", ulBufferSize);
  833. dprintf (" BufferCount = %ld\n", (ULONG) ReadField (NumberOfBuffers));
  834. dprintf (" MaximumBuffers = %ld\n", (ULONG) ReadField (MaximumBuffers));
  835. dprintf (" MinimumBuffers = %ld\n", (ULONG) ReadField (MinimumBuffers));
  836. dprintf (" EventsLost = %ld\n", (ULONG) ReadField (EventsLost));
  837. dprintf (" LogBuffersLost = %ld\n", (ULONG) ReadField (LogBuffersLost));
  838. dprintf (" RealTimeBuffersLost=%ld\n", (ULONG) ReadField (RealTimeBuffersLost));
  839. dprintf (" BuffersAvailable = %ld\n", (ULONG) ReadField (BuffersAvailable));
  840. dprintf (" LastFlushedBuffer = %ld\n", (ULONG) ReadField (LastFlushedBuffer));
  841. }
  842. dprintf (" Processing Global List: 0");
  843. tarBufferListPointer = 0;
  844. GetFieldValue (tarAddress, "_WMI_LOGGER_CONTEXT", "GlobalList.Next", tarBufferListPointer);
  845. while (tarBufferListPointer != 0) {
  846. WMI_BUFFER_SOURCE source;
  847. ULONG ulCpuNumber;
  848. int iBufferUses;
  849. int iProcessBuffer;
  850. TARGET_ADDRESS tarBufferPointer;
  851. ULONG ulFree, ulInUse, ulFlush;
  852. iBufferUses = 0;
  853. ulCpuNumber = ~((ULONG) 0);
  854. iProcessBuffer = FALSE;
  855. source = WMIBS_TRANSITION_LIST;
  856. tarBufferPointer = tarBufferListPointer - tarBufferListOffset;
  857. dprintf ("\b\b\b%3d", ++ulLoopCount);
  858. InitTypeRead (tarBufferPointer, _WMI_BUFFER_HEADER);
  859. ulFree = (ULONG) ReadField (State.Free);
  860. ulInUse = (ULONG) ReadField (State.InUse);
  861. ulFlush = (ULONG) ReadField (State.Flush);
  862. // Decide on Buffer Processing based on Use Flags and 'Sources'
  863. if (ulFree ) iBufferUses += 1;
  864. if (ulInUse) iBufferUses += 2;
  865. if (ulFlush) iBufferUses += 4;
  866. switch (iBufferUses) {
  867. case 0: { // No bits set, never used.
  868. break;
  869. }
  870. case 1: { // Free
  871. iProcessBuffer = Sources.FreeBuffers;
  872. source = WMIBS_FREE_LIST;
  873. break;
  874. }
  875. case 2: { // InUse
  876. iProcessBuffer = Sources.ActiveBuffers;
  877. source = WMIBS_CURRENT_LIST;
  878. //source = WMIBS_FLUSH_LIST;
  879. break;
  880. }
  881. case 3: { // MULTIPLE BITS SET, ERROR
  882. dprintf ("\n***Error, Inconsistent Flags Bits (Free,InUse) Set.***\n");
  883. break;
  884. }
  885. case 4: { // Flush
  886. iProcessBuffer = Sources.FlushBuffers;
  887. source = WMIBS_FLUSH_LIST;
  888. break;
  889. }
  890. case 5: {
  891. dprintf ("\n***Error, Inconsistent Flags Bits (Free,Flush) Set.***\n");
  892. break;
  893. }
  894. case 6: {
  895. dprintf ("\n***Error, Inconsistent Flags Bits (InUse,Flush) Set.***\n");
  896. break;
  897. }
  898. case 7: {
  899. dprintf ("\n***Error, Inconsistent Flags Bits (Free,InUse,Flush) Set.***\n");
  900. break;
  901. }
  902. }
  903. // ProcessBuffer as Decided Above
  904. if (iProcessBuffer) {
  905. ulBufferCount++;
  906. Procedure (Context, tarBufferPointer, ulBufferSize, ulCpuNumber, ulAlignment, source);
  907. }
  908. if (GetFieldValue (tarBufferPointer,
  909. "_WMI_BUFFER_HEADER", "GlobalEntry",
  910. tarBufferListPointer) != 0) {
  911. dprintf ("\n***Error Following Global List.***\n");
  912. tarBufferListPointer = 0;
  913. }
  914. }
  915. dprintf (" Buffers\n");
  916. // Return w/ BufferCount
  917. return (ulBufferCount);
  918. } // wmiKdProcessNonblockingBuffers
  919. //+---------------------------------------------------------------------------
  920. //
  921. // Function: ULONG wmiKdProcessBlockingBuffers
  922. //
  923. // Synopsis: Calls Caller-Supplied Procedure for each Buffer in Locations/
  924. // Lists as specified by 'Sources'. Walks lists, Enumerates
  925. // CPU's buffers, and handles 'Transition Buffer' logic.
  926. //
  927. // Arguments: LoggerId
  928. // LoggerContext
  929. // Procedure
  930. // Context
  931. // Sources
  932. //
  933. // Returns: ULONG: Number of Buffers Processed
  934. //
  935. // History: 04-05-2000 glennp Created
  936. //
  937. // Notes: Sources also controls informational printing
  938. //
  939. //----------------------------------------------------------------------------
  940. ULONG
  941. wmiKdProcessBlockingBuffers(
  942. ULONG LoggerId,
  943. TARGET_ADDRESS LoggerContext,
  944. WMITRACING_KD_LISTENTRY_PROC Procedure,
  945. PVOID Context,
  946. WMITRACING_BUFFER_SOURCES Sources
  947. )
  948. {
  949. TARGET_ADDRESS tarAddress;
  950. ULONG pointerSize;
  951. PROCESSORINFO ProcessorInfo;
  952. ULONG ulOrdinal;
  953. ULONG ulAlignment;
  954. ULONG ulBufferSize;
  955. ULONG ulBufferCount;
  956. ULONG ulBufferNumber;
  957. ULONG ulBufferCountTotal;
  958. ULONG tarFlushListOffset;
  959. ULONG tarBufferListOffset;
  960. // Get Pointer to Context Structure
  961. tarAddress = LoggerContext;
  962. if (tarAddress == 0) return (0);
  963. // Initialize Locals
  964. ulBufferNumber = 0;
  965. ulBufferCount = 0;
  966. ulBufferCountTotal = 0;
  967. // Get Sizes, Offsets, Alignments from Target
  968. pointerSize = GetTypeSize ("PVOID");
  969. ulAlignment = GetWmiTraceAlignment ();
  970. GetFieldOffset ("_WMI_BUFFER_HEADER", "Entry", &tarBufferListOffset);
  971. GetFieldOffset ("_WMI_LOGGER_CONTEXT", "FlushList", &tarFlushListOffset);
  972. // Optionally Print LoggerId, Context Address, Logger name
  973. if (Sources.PrintInformation) {
  974. dprintf (" Logger Id %2d @ 0x%P Named '", LoggerId, tarAddress);
  975. printUnicodeFromStruct (tarAddress, "_WMI_LOGGER_CONTEXT", "LoggerName");
  976. dprintf ("'\n");
  977. }
  978. // Setup ReadField's Context, Find Buffer Size
  979. InitTypeRead (tarAddress, _WMI_LOGGER_CONTEXT);
  980. ulBufferSize = (ULONG) ReadField (BufferSize);
  981. // Optionally Print a few interesting numbers
  982. if (Sources.PrintInformation) {
  983. dprintf (" Alignment = %ld\n", ulAlignment);
  984. dprintf (" BufferSize = %ld\n", ulBufferSize);
  985. dprintf (" BufferCount = %ld\n", (ULONG) ReadField (NumberOfBuffers));
  986. dprintf (" MaximumBuffers = %ld\n", (ULONG) ReadField (MaximumBuffers));
  987. dprintf (" MinimumBuffers = %ld\n", (ULONG) ReadField (MinimumBuffers));
  988. dprintf (" EventsLost = %ld\n", (ULONG) ReadField (EventsLost));
  989. dprintf (" LogBuffersLost = %ld\n", (ULONG) ReadField (LogBuffersLost));
  990. dprintf (" RealTimeBuffersLost=%ld\n", (ULONG) ReadField (RealTimeBuffersLost));
  991. dprintf (" BuffersAvailable = %ld\n", (ULONG) ReadField (BuffersAvailable));
  992. dprintf (" LastFlushedBuffer = %ld\n", (ULONG) ReadField (LastFlushedBuffer));
  993. }
  994. // Setup for Checks against TransitionBuffer Address IF REQUESTED
  995. TransitionBuffer = 0;
  996. if (Sources.TransitionBuffer) {
  997. TARGET_ADDRESS tarTransitionBuffer;
  998. tarTransitionBuffer = ReadField (TransitionBuffer);
  999. if ((tarTransitionBuffer != 0) &&
  1000. (tarTransitionBuffer != (tarAddress + tarFlushListOffset))) {
  1001. ULONG tarTransitionBufferOffset;
  1002. GetFieldOffset ("_WMI_BUFFER_HEADER", "Entry", &tarTransitionBufferOffset);
  1003. tarTransitionBuffer = tarAddress - tarTransitionBufferOffset;
  1004. TransitionBuffer = tarTransitionBuffer;
  1005. }
  1006. }
  1007. // Access the Free Queue Buffers IF REQUESTED
  1008. if (Sources.FreeBuffers) {
  1009. ULONG tarFreeListOffset;
  1010. GetFieldOffset ("_WMI_LOGGER_CONTEXT", "FreeList", &tarFreeListOffset);
  1011. dprintf (" Processing FreeQueue: ");
  1012. ulBufferCount = wmiKdProcessLinkList (tarAddress + tarFreeListOffset,
  1013. Procedure, Context, ulBufferSize, ulAlignment, WMIBS_FREE_LIST,
  1014. tarBufferListOffset, Sources.PrintProgressIndicator);
  1015. dprintf ("%ld Buffers\n", ulBufferCount);
  1016. ulBufferCountTotal += ulBufferCount;
  1017. }
  1018. // Access the Flush Queue Buffers IF REQUESTED
  1019. if (Sources.FlushBuffers) {
  1020. dprintf (" Processing FlushQueue: ");
  1021. ulBufferCount = wmiKdProcessLinkList (tarAddress + tarFlushListOffset,
  1022. Procedure, Context, ulBufferSize, ulAlignment, WMIBS_FLUSH_LIST,
  1023. tarBufferListOffset, Sources.PrintProgressIndicator);
  1024. dprintf ("%ld Buffers\n", ulBufferCount);
  1025. ulBufferCountTotal += ulBufferCount;
  1026. }
  1027. // Access the 'Live' buffers (one per cpu) IF REQUESTED
  1028. if (Sources.ActiveBuffers) {
  1029. TARGET_ADDRESS tarProcessorArrayAddress;
  1030. GetFieldValue (tarAddress,"_WMI_LOGGER_CONTEXT", "ProcessorBuffers", tarProcessorArrayAddress);
  1031. Ioctl (IG_KD_CONTEXT, &ProcessorInfo, sizeof (ProcessorInfo));
  1032. for (ProcessorInfo.Processor = 0;
  1033. ProcessorInfo.Processor < ProcessorInfo.NumberProcessors;
  1034. ++ProcessorInfo.Processor) {
  1035. TARGET_ADDRESS tarProcessorPointer;
  1036. ReadPtr (tarProcessorArrayAddress + ProcessorInfo.Processor * pointerSize,
  1037. &tarProcessorPointer);
  1038. dprintf (" Cpu %d Buffer Header @ 0x%P ",
  1039. ProcessorInfo.Processor, tarProcessorPointer);
  1040. Procedure (Context, tarProcessorPointer, ulBufferSize,
  1041. ProcessorInfo.Processor, ulAlignment, WMIBS_CURRENT_LIST);
  1042. ulBufferCountTotal += 1;
  1043. dprintf (" \b\n");
  1044. } // Cpu Loop
  1045. }
  1046. // Process the Transition Entry (if any). Note 'IF REQUESTED' test above in Setup
  1047. if (TransitionBuffer != 0) {
  1048. dprintf (" Transition Buffer @ 0x%P ", TransitionBuffer);
  1049. Procedure (Context, TransitionBuffer, ulBufferSize, ~0, ulAlignment, WMIBS_TRANSITION_LIST);
  1050. ulBufferCountTotal += 1;
  1051. }
  1052. // Return w/ BufferCount
  1053. return (ulBufferCountTotal);
  1054. } // wmiKdProcessBlockingBuffers
  1055. //+---------------------------------------------------------------------------
  1056. //
  1057. // Function: ULONG wmiKdProcessBuffers
  1058. //
  1059. // Synopsis: Decides if the target system is using doubly-linked (blocking)
  1060. // or singly-linked (non-blocking) lists of buffers. Then it
  1061. // calls the appropriate Buffer-Walking routine. They:
  1062. // Call Caller-Supplied Procedure for each Buffer in Locations/
  1063. // Lists as specified by 'Sources'. Walk lists, Enumerates
  1064. // CPU's buffers, and handles 'Transition Buffer' logic.
  1065. //
  1066. // Arguments: LoggerId
  1067. // LoggerContext
  1068. // Procedure
  1069. // Context
  1070. // Sources
  1071. //
  1072. // Returns: ULONG: Number of Buffers Processed
  1073. //
  1074. // History: 04-05-2000 glennp Created
  1075. //
  1076. // Notes: Sources also controls informational printing
  1077. //
  1078. //----------------------------------------------------------------------------
  1079. ULONG
  1080. wmiKdProcessBuffers(
  1081. ULONG LoggerId,
  1082. TARGET_ADDRESS LoggerContext,
  1083. WMITRACING_KD_LISTENTRY_PROC Procedure,
  1084. PVOID Context,
  1085. WMITRACING_BUFFER_SOURCES Sources
  1086. )
  1087. {
  1088. ULONG ulBufferCountTotal;
  1089. int iBufferMechanism;
  1090. ULONG tarGlobalListOffset;
  1091. ULONG tarTransitionBufferOffset;
  1092. iBufferMechanism = 0;
  1093. ulBufferCountTotal = 0;
  1094. if ((GetFieldOffset ("_WMI_LOGGER_CONTEXT", "GlobalList", &tarGlobalListOffset) == 0) &&
  1095. (tarGlobalListOffset != 0)) {
  1096. iBufferMechanism += 1;
  1097. }
  1098. if ((GetFieldOffset ("_WMI_LOGGER_CONTEXT", "TransitionBuffer", &tarTransitionBufferOffset) == 0) &&
  1099. (tarTransitionBufferOffset != 0)) {
  1100. iBufferMechanism += 2;
  1101. }
  1102. switch (iBufferMechanism) {
  1103. case 0: { // Neither, ???
  1104. dprintf ("Unable to determine buffer mechanism. "
  1105. "Check for complete symbol availability.\n");
  1106. break;
  1107. }
  1108. case 1: { // Global, no Transition
  1109. ulBufferCountTotal = wmiKdProcessNonblockingBuffers (LoggerId, LoggerContext,
  1110. Procedure, Context, Sources);
  1111. break;
  1112. }
  1113. case 2: { // Transition, no Global
  1114. ulBufferCountTotal = wmiKdProcessBlockingBuffers (LoggerId, LoggerContext,
  1115. Procedure, Context, Sources);
  1116. break;
  1117. }
  1118. case 3: { // Both, ???
  1119. dprintf ("Unable to determine buffer mechanism. "
  1120. "Check for new wmiTrace debugger extension. GO = %d, TB = %d\n",
  1121. tarGlobalListOffset, tarTransitionBufferOffset);
  1122. break;
  1123. }
  1124. }
  1125. // Return w/ BufferCount
  1126. return (ulBufferCountTotal);
  1127. } // wmiKdProcessBuffers
  1128. //+---------------------------------------------------------------------------
  1129. //
  1130. // Function: VOID wmiLogDump
  1131. //
  1132. // Synopsis: callable procedure to dump the in-memory part of a tracelog.
  1133. // Caller can supply three procedures to:
  1134. // 1. Filter and Select the Sort Key for VMI Events,
  1135. // 2. Compare the Sort Keys, and
  1136. // 3. Print the Output for each Selected Event.
  1137. // this procedure is called by the built-in extension logdump.
  1138. //
  1139. // Arguments: LoggerId -> the Id of the logger stream to process
  1140. // Context <OMITTED>
  1141. // GuidListHeadPtr -> to a list of MOF Guids from GetTraceGuids
  1142. // Filter -> to a replacement Filter procedure
  1143. // Compare -> to a replacement Compare (for Sort) procedure
  1144. // Output -> to a replacement Output procedure
  1145. //
  1146. // Returns: VOID
  1147. //
  1148. // History: 04-05-2000 glennp Created
  1149. //
  1150. //----------------------------------------------------------------------------
  1151. VOID wmiLogDump(
  1152. ULONG LoggerId,
  1153. PVOID UserContext,
  1154. PLIST_ENTRY GuidListHeadPtr,
  1155. WMITRACING_KD_FILTER Filter,
  1156. WMITRACING_KD_COMPARE Compare,
  1157. WMITRACING_KD_OUTPUT Output
  1158. )
  1159. {
  1160. ULONG ulOrdinal;
  1161. ULONG ulSortIndex;
  1162. ULONG ulBufferSize;
  1163. ULONG ulBufferCountTotal;
  1164. ULONG ulAlignment;
  1165. TARGET_ADDRESS tarAddress;
  1166. PCHAR locBufferAddress;
  1167. TARGET_ADDRESS lastBufferAddress;
  1168. struct sttSortControl stSortControl;
  1169. struct sttTraceContext stTraceContext;
  1170. WMITRACING_BUFFER_SOURCES stSources;
  1171. // Replace NULL procedures w/ defaults
  1172. if (Filter == NULL) Filter = wmiDefaultFilter;
  1173. if (Compare == NULL) Compare = wmiDefaultCompare;
  1174. if (Output == NULL) Output = wmiDefaultOutput;
  1175. // Initialize Locals
  1176. memset (&stSortControl, 0, sizeof (stSortControl));
  1177. memset (&stTraceContext, 0, sizeof (stTraceContext));
  1178. stTraceContext.pstSortControl = &stSortControl;
  1179. stTraceContext.UserContext = UserContext;
  1180. //stTraceContext.Ordinal = 0;
  1181. stTraceContext.Filter = Filter;
  1182. // Select (All) Sources
  1183. stSources.FreeBuffers = 1;
  1184. stSources.FlushBuffers = 1;
  1185. stSources.ActiveBuffers = 1;
  1186. stSources.TransitionBuffer = 1;
  1187. // Print Summary and ProgressIndicator
  1188. stSources.PrintInformation = 1;
  1189. stSources.PrintProgressIndicator = 1;
  1190. // Print Intro Message
  1191. dprintf ("(WmiTrace)LogDump for Log Id %ld\n", LoggerId);
  1192. // Get Pointer to Logger Context
  1193. tarAddress = FindLoggerContext (LoggerId);
  1194. ulAlignment = GetWmiTraceAlignment ();
  1195. // Filter and Gather all Messages we want
  1196. ulBufferCountTotal = wmiKdProcessBuffers (LoggerId, tarAddress,
  1197. wmiDumpProc, &stTraceContext, stSources);
  1198. // Sort the Entries just Gathered
  1199. qsort (stSortControl.pstSortEntries, stSortControl.CurEntries,
  1200. sizeof (stSortControl.pstSortEntries[0]), Compare);
  1201. if (stSortControl.CurEntries > 0) {
  1202. dprintf ("LOGGED MESSAGES (%ld):\n", stSortControl.CurEntries);
  1203. }
  1204. // Allocate Buffer
  1205. GetFieldValue (tarAddress, "_WMI_LOGGER_CONTEXT", "BufferSize", ulBufferSize);
  1206. lastBufferAddress = 0; // For the buffer 'cache' (one item for now)
  1207. locBufferAddress = LocalAlloc (LPTR, ulBufferSize);
  1208. if (locBufferAddress == NULL) {
  1209. dprintf ("FAILED TO ALLOCATE NEEDED BUFFER!\n");
  1210. goto Cleanup;
  1211. }
  1212. // Print each (Sorted) Entry
  1213. for (ulSortIndex = 0; ulSortIndex < stSortControl.CurEntries; ++ulSortIndex) {
  1214. const WMITRACING_KD_SORTENTRY *sortEntry;
  1215. union {
  1216. EVENT_TRACE stEvent;
  1217. CHAR caEvent[4096];
  1218. } u;
  1219. if (CheckControlC()) break;
  1220. sortEntry = &stSortControl.pstSortEntries[ulSortIndex];
  1221. // Read the entire buffer if not same as last
  1222. if (lastBufferAddress != sortEntry->Address) {
  1223. {
  1224. ULONG ulInfo;
  1225. ULONG ulBytesRead;
  1226. // Read Buffer
  1227. ulBytesRead = 0;
  1228. lastBufferAddress = sortEntry->Address;
  1229. ulInfo =
  1230. ReadMemory (lastBufferAddress, locBufferAddress, ulBufferSize, &ulBytesRead);
  1231. if ((!ulInfo) || (ulBytesRead != ulBufferSize)) {
  1232. dprintf ("Failed to (Re)Read Buffer @ %P.\n", lastBufferAddress);
  1233. continue; // Try for others
  1234. }
  1235. }
  1236. {
  1237. WMIBUFFERINFO stBufferInfo;
  1238. // Perform Fixup
  1239. memset (&stBufferInfo, 0, sizeof (stBufferInfo));
  1240. stBufferInfo.BufferSource = sortEntry->BufferSource;
  1241. stBufferInfo.Buffer = locBufferAddress;
  1242. stBufferInfo.BufferSize = ulBufferSize;
  1243. stBufferInfo.ProcessorNumber = sortEntry->CpuNo;
  1244. stBufferInfo.Alignment = ulAlignment;
  1245. WmiGetFirstTraceOffset (&stBufferInfo);
  1246. }
  1247. }
  1248. // Get a consistant header
  1249. WmiParseTraceEvent (locBufferAddress, sortEntry->Offset, sortEntry->HeaderType,
  1250. &u, sizeof (u));
  1251. // Output the Entry
  1252. Output (UserContext, GuidListHeadPtr, sortEntry, &u.stEvent);
  1253. }
  1254. Cleanup:
  1255. // Free Buffer
  1256. LocalFree (locBufferAddress);
  1257. // Print Summary
  1258. dprintf ("Total of %ld Messages from %ld Buffers\n",
  1259. stSortControl.CurEntries,
  1260. ulBufferCountTotal);
  1261. // Free the sort elements (pointers + keys)
  1262. free (stSortControl.pstSortEntries);
  1263. return;
  1264. } // wmiLogDump
  1265. //+---------------------------------------------------------------------------
  1266. //
  1267. // Function: DECLARE_API(help)
  1268. //
  1269. // Synopsis: list available functions and syntax
  1270. //
  1271. // Arguments: <NONE>
  1272. //
  1273. // Returns: <VOID>
  1274. //
  1275. // History: 2-17-2000 glennp Created
  1276. //
  1277. // Notes:
  1278. //
  1279. //----------------------------------------------------------------------------
  1280. DECLARE_API( help )
  1281. {
  1282. dprintf("WMI Tracing Kernel Debugger Extensions\n");
  1283. dprintf(" logdump <LoggerId> [<guid file name>] - Dump the in-memory portion of a log file\n");
  1284. dprintf(" logsave <LoggerId> <Save file name> - Save the in-memory portion of a log file in binary form\n");
  1285. dprintf(" strdump [<LoggerId>] - Dump the Wmi Trace Event Structures\n");
  1286. }
  1287. //+---------------------------------------------------------------------------
  1288. //
  1289. // Function: DECLARE_API(logdump)
  1290. //
  1291. // Synopsis: LOG DUMP: Dumps Trace Messages from a Log Stream to Stdout
  1292. //
  1293. // Arguments: <Stream Number> [<MofData.Guid File Name>]
  1294. //
  1295. // Returns: <VOID>
  1296. //
  1297. // History: 2-17-2000 glennp Created
  1298. //
  1299. // Notes:
  1300. //
  1301. //----------------------------------------------------------------------------
  1302. DECLARE_API( logdump )
  1303. {
  1304. ULONG ulStatus;
  1305. TARGET_ADDRESS tarAddress;
  1306. ULONG ulLoggerId;
  1307. LPSTR pszGuidFileName;
  1308. PLIST_ENTRY GuidListHeadPtr;
  1309. const CHAR *argPtr;
  1310. size_t sztLen;
  1311. CHAR caFileName[256];
  1312. // Defaults
  1313. ulLoggerId = 1;
  1314. GuidListHeadPtr = NULL;
  1315. pszGuidFileName = "FmtData.txt";
  1316. // LoggerId ?
  1317. if (args && args[0]) {
  1318. ulLoggerId = (ULONG) GetExpression (args);
  1319. }
  1320. // LoggerId ?
  1321. argPtr = args + strspn (args, " \t\n");
  1322. sztLen = strspn (argPtr, "0123456789");
  1323. if (sztLen > 0) {
  1324. // ulLoggerId = atol (argPtr);
  1325. argPtr += sztLen;
  1326. }
  1327. // Guid Definition File
  1328. argPtr = argPtr + strspn (argPtr, " \t\n,");
  1329. if (strlen (argPtr)) {
  1330. sztLen = strcspn (argPtr, " \t\n,");
  1331. memcpy (caFileName, argPtr, sztLen);
  1332. caFileName[sztLen] = '\000';
  1333. pszGuidFileName = caFileName;
  1334. }
  1335. // Show LoggerId, FileName
  1336. dprintf ("WMI Generic Trace Dump: Debugger Extension. LoggerId = %ld, Guidfile = '%s'\n",
  1337. ulLoggerId, pszGuidFileName);
  1338. // Open Guid File, Dump Log, Cleanup
  1339. GuidListHeadPtr = NULL;
  1340. ulStatus = GetTraceGuids ((TCHAR *) pszGuidFileName, &GuidListHeadPtr);
  1341. if (ulStatus == 0) {
  1342. dprintf ("Failed to open Guid file '%hs'\n", pszGuidFileName);
  1343. } else {
  1344. dprintf ("Opened Guid File '%hs' with %d Entries.\n",
  1345. pszGuidFileName, ulStatus);
  1346. wmiLogDump (ulLoggerId, NULL, GuidListHeadPtr, NULL, NULL, NULL);
  1347. CleanupTraceEventList (GuidListHeadPtr);
  1348. }
  1349. return;
  1350. } // logdump
  1351. //+---------------------------------------------------------------------------
  1352. //
  1353. // Function: DECLARE_API(logsave)
  1354. //
  1355. // Synopsis: LOG DUMP: Dumps Trace Messages from a Log Stream to Stdout
  1356. //
  1357. // Arguments: <Stream Number> [<MofData.Guid File Name>]
  1358. //
  1359. // Returns: <VOID>
  1360. //
  1361. // History: 2-17-2000 glennp Created
  1362. //
  1363. // Notes:
  1364. //
  1365. //----------------------------------------------------------------------------
  1366. DECLARE_API( logsave )
  1367. {
  1368. ULONG ulStatus;
  1369. TARGET_ADDRESS tarAddress;
  1370. ULONG ulLoggerId;
  1371. LPSTR pszSaveFileName;
  1372. const CHAR *argPtr;
  1373. size_t sztLen;
  1374. CHAR caFileName[256];
  1375. // Defaults
  1376. ulLoggerId = 1;
  1377. pszSaveFileName = "LogData.elg";
  1378. // LoggerId ?
  1379. if (args && args[0]) {
  1380. ulLoggerId = (ULONG) GetExpression (args);
  1381. }
  1382. // Point beyond LoggerId
  1383. argPtr = args + strspn (args, " \t\n");
  1384. argPtr += strspn (argPtr, "0123456789");
  1385. // Save File
  1386. argPtr = argPtr + strspn (argPtr, " \t\n,");
  1387. if (strlen (argPtr)) {
  1388. sztLen = strcspn (argPtr, " \t\n,");
  1389. memcpy (caFileName, argPtr, sztLen);
  1390. caFileName[sztLen] = '\000';
  1391. pszSaveFileName = caFileName;
  1392. }
  1393. // Show LoggerId, FileName
  1394. dprintf ("WMI Trace Save: Debugger Extension. LoggerId = %ld, Save File = '%s'\n",
  1395. ulLoggerId, pszSaveFileName);
  1396. // Get Pointer to Logger Context
  1397. tarAddress = FindLoggerContext (ulLoggerId);
  1398. // Check if LoggerId Good
  1399. if (tarAddress == 0) {
  1400. dprintf ("Failed to Find Logger\n");
  1401. } else {
  1402. FILE *pfSaveFile;
  1403. // Open Guid File, Dump Log, Cleanup
  1404. pfSaveFile = fopen (pszSaveFileName, "ab");
  1405. if (pfSaveFile == NULL) {
  1406. dprintf ("Failed to Open Save File '%hs'\n", pszSaveFileName);
  1407. } else {
  1408. WMITRACING_BUFFER_SOURCES stSources;
  1409. struct sttSaveContext stSaveContext;
  1410. ULONG ulTotalBufferCount;
  1411. ULONG ulRealTime;
  1412. // See if we are in "RealTime" mode (if so, we'll save FreeBuffers too)
  1413. if (GetFieldValue (tarAddress,
  1414. "_WMI_LOGGER_CONTEXT",
  1415. "LoggerModeFlags.RealTime",
  1416. ulRealTime)) {
  1417. dprintf ("Unable to Retrieve 'RealTime' Flag. Assuming Realtime Mode.\n");
  1418. ulRealTime = 1; // Better to get too many than too few.
  1419. }
  1420. //Write Header
  1421. wmiKdWriteFileHeader (pfSaveFile, ulLoggerId, tarAddress);
  1422. // Select Sources
  1423. stSources.FreeBuffers = (ulRealTime) ? 1 : 0;
  1424. stSources.FlushBuffers = 1;
  1425. stSources.ActiveBuffers = 1;
  1426. stSources.TransitionBuffer = 1;
  1427. stSources.PrintInformation = 1;
  1428. stSources.PrintProgressIndicator = 1;
  1429. // Setup SaveContext
  1430. stSaveContext.pfSaveFile = pfSaveFile;
  1431. // Write Buffers
  1432. ulTotalBufferCount = wmiKdProcessBuffers (ulLoggerId, tarAddress,
  1433. wmiSaveProc, &stSaveContext, stSources);
  1434. dprintf ("Saved %d Buffers\n", ulTotalBufferCount);
  1435. // Close
  1436. fclose (pfSaveFile);
  1437. }
  1438. }
  1439. return;
  1440. } // logdump
  1441. //+---------------------------------------------------------------------------
  1442. //
  1443. // Function: DECLARE_API(strdump)
  1444. //
  1445. // Synopsis: STRucture DUMP: dumps generic info (no arg) or stream info (arg)
  1446. //
  1447. // Arguments: [<Stream Number>]
  1448. //
  1449. // Returns: <VOID>
  1450. //
  1451. // History: 2-17-2000 glennp Created
  1452. //
  1453. // Notes:
  1454. //
  1455. //----------------------------------------------------------------------------
  1456. DECLARE_API( strdump )
  1457. /*
  1458. * dump the structures for trace logging
  1459. * strdump [<LoggerId>]
  1460. * If <LoggerId> present, dump structs for that Id
  1461. * Else dump generic structs
  1462. */
  1463. {
  1464. TARGET_ADDRESS tarAddress;
  1465. DWORD dwRead, Flags;
  1466. ULONG ulLoggerId;
  1467. ULONG ulMaxLoggerId;
  1468. ULONG pointerSize;
  1469. // Defaults
  1470. ulLoggerId = ~0;
  1471. pointerSize = GetTypeSize ("PVOID");
  1472. // LoggerId ?
  1473. if (args && args[0]) {
  1474. ulLoggerId = (ULONG) GetExpression (args);
  1475. }
  1476. if (ulLoggerId == ~0) {
  1477. dprintf ("(WmiTracing)StrDump Generic\n");
  1478. tarAddress = FindLoggerContextArray (&ulMaxLoggerId);
  1479. dprintf (" LoggerContext Array @ 0x%P [%d Elements]\n",
  1480. tarAddress, ulMaxLoggerId);
  1481. if (tarAddress) {
  1482. for (ulLoggerId = 0; ulLoggerId < ulMaxLoggerId; ++ulLoggerId) {
  1483. TARGET_ADDRESS contextAddress;
  1484. contextAddress = tarAddress + pointerSize * ulLoggerId;
  1485. /*if (*/ReadPointer (contextAddress, &contextAddress)/*) {*/;
  1486. //dprintf ("UNABLE TO READ POINTER in ARRAY of POINTERS!, Addr = 0x%P\n", contextAddress);
  1487. /*} else*/ if (contextAddress != 0) {
  1488. dprintf (" Logger Id %2d @ 0x%P Named '", ulLoggerId, contextAddress);
  1489. printUnicodeFromStruct (contextAddress, "_WMI_LOGGER_CONTEXT", "LoggerName");
  1490. dprintf ("'\n");
  1491. }
  1492. }
  1493. }
  1494. } else {
  1495. dprintf ("(WmiTracing)StrDump for Log Id %ld\n", ulLoggerId);
  1496. tarAddress = FindLoggerContext (ulLoggerId);
  1497. if (tarAddress != 0) {
  1498. dprintf (" Logger Id %2d @ 0x%P Named '", ulLoggerId, tarAddress);
  1499. printUnicodeFromStruct (tarAddress, "_WMI_LOGGER_CONTEXT", "LoggerName");
  1500. dprintf ("'\n");
  1501. InitTypeRead (tarAddress, _WMI_LOGGER_CONTEXT);
  1502. dprintf (" BufferSize = %ld\n", (ULONG) ReadField (BufferSize));
  1503. dprintf (" BufferCount = %ld\n", (ULONG) ReadField (NumberOfBuffers));
  1504. dprintf (" MaximumBuffers = %ld\n", (ULONG) ReadField (MaximumBuffers));
  1505. dprintf (" MinimumBuffers = %ld\n", (ULONG) ReadField (MinimumBuffers));
  1506. dprintf (" EventsLost = %ld\n", (ULONG) ReadField (EventsLost));
  1507. dprintf (" LogBuffersLost = %ld\n", (ULONG) ReadField (LogBuffersLost));
  1508. dprintf (" RealTimeBuffersLost=%ld\n", (ULONG) ReadField (RealTimeBuffersLost));
  1509. dprintf (" BuffersAvailable = %ld\n", (ULONG) ReadField (BuffersAvailable));
  1510. dprintf (" LastFlushedBuffer = %ld\n", (ULONG) ReadField (LastFlushedBuffer));
  1511. dprintf (" LoggerId = 0x%02lX\n", (ULONG) ReadField (LoggerId));
  1512. dprintf (" CollectionOn = %ld\n", (ULONG) ReadField (CollectionOn));
  1513. dprintf (" KernelTraceOn = %ld\n", (ULONG) ReadField (KernelTraceOn));
  1514. dprintf (" EnableFlags = 0x%08lX\n", (ULONG) ReadField (EnableFlags));
  1515. dprintf (" MaximumFileSize = %ld\n", (ULONG) ReadField (MaximumFileSize));
  1516. dprintf (" LogFileMode = 0x%08lX\n", (ULONG) ReadField (LogFileMode));
  1517. dprintf (" FlushTimer = %I64u\n", ReadField (FlushTimer));
  1518. dprintf (" FirstBufferOffset = %I64u\n", ReadField (FirstBufferOffset));
  1519. dprintf (" ByteOffset = %I64u\n", ReadField (ByteOffset));
  1520. dprintf (" BufferAgeLimit = %I64d\n", ReadField (BufferAgeLimit));
  1521. dprintf (" LoggerName = '");
  1522. printUnicodeFromStruct (tarAddress, "_WMI_LOGGER_CONTEXT", "LoggerName");
  1523. dprintf ( "'\n");
  1524. dprintf (" LogFileName = '");
  1525. printUnicodeFromStruct (tarAddress, "_WMI_LOGGER_CONTEXT", "LogFileName");
  1526. dprintf ( "'\n");
  1527. }
  1528. }
  1529. return;
  1530. }