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.

2435 lines
81 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 <tchar.h>
  39. #include "wmiTrace.h"
  40. #pragma hdrstop
  41. typedef ULONG64 TARGET_ADDRESS;
  42. typedef VOID (*WMITRACING_KD_LISTENTRY_PROC)
  43. ( PVOID Context
  44. , TARGET_ADDRESS Buffer
  45. , ULONG Length
  46. , ULONG CpuNo
  47. , ULONG Align
  48. , WMI_BUFFER_SOURCE Source
  49. );
  50. typedef struct _WMITRACING_BUFFER_SOURCES {
  51. ULONG FreeBuffers:1;
  52. ULONG FlushBuffers:1;
  53. ULONG ActiveBuffers:1;
  54. ULONG TransitionBuffer:1;
  55. ULONG PrintInformation:1;
  56. ULONG PrintProgressIndicator:1;
  57. } WMITRACING_BUFFER_SOURCES;
  58. struct sttSortControl
  59. {
  60. ULONG MaxEntries;
  61. ULONG CurEntries;
  62. WMITRACING_KD_SORTENTRY *pstSortEntries;
  63. };
  64. struct sttTraceContext
  65. {
  66. struct sttSortControl *pstSortControl;
  67. PVOID UserContext;
  68. ULONG BufferSize;
  69. ULONG Ordinal;
  70. WMITRACING_KD_FILTER Filter;
  71. };
  72. struct sttSaveContext
  73. {
  74. FILE *pfSaveFile;
  75. };
  76. extern DBGKD_GET_VERSION64 KernelVersionData;
  77. TARGET_ADDRESS TransitionBuffer;
  78. //Global guid filename
  79. //LPSTR g_pszGuidFileName = "default.tmf";
  80. CHAR g_pszGuidFileName[MAX_PATH] = "default.tmf";
  81. //Global guid list head pointer
  82. PLIST_ENTRY g_GuidListHeadPtr = NULL;
  83. //Global value to determine if dynamic printing is on or off
  84. ULONG g_ulPrintDynamicMessages = 1;
  85. //Global handle to TracePrt.dll module
  86. HMODULE g_hmTracePrtHandle = NULL;
  87. //Global handle to WmiTrace.dll modlue
  88. HMODULE g_hmWmiTraceHandle = NULL;
  89. //Global proc address of TracePrt's FormatTraceEvent function
  90. FARPROC g_fpFormatTraceEvent = NULL;
  91. //Global proc address of TracePrt's SetTraceFormatParameter function
  92. FARPROC g_fpSetTraceFormatParameter = NULL;
  93. //Global proc address of TracePrt's GetTraceFormatParameter function
  94. FARPROC g_fpGetTraceFormatSearchPath = NULL;
  95. //Global proc address of TracePrt's GetTraceGuids function
  96. FARPROC g_fpGetTraceGuids = NULL;
  97. //Global proc address of TracePrt's CleanupTraceEventList function
  98. FARPROC g_fpCleanupTraceEventList = NULL;
  99. //Prototype for private function to get handle to TracePrt DLL
  100. HMODULE getTracePrtHandle();
  101. //Prototype for private function to get the address of a function in the TracePrt DLL
  102. FARPROC GetAddr(LPCSTR lpProcName);
  103. NTSTATUS
  104. EtwpDeinitializeDll ();
  105. NTSTATUS
  106. EtwpInitializeDll ();
  107. #ifdef UNICODE
  108. #define FormatTraceEventString "FormatTraceEventW"
  109. #define GetTraceGuidsString "GetTraceGuidsW"
  110. #else
  111. #define FormatTraceEventString "FormatTraceEventA"
  112. #define GetTraceGuidsString "GetTraceGuidsA"
  113. #endif
  114. //+---------------------------------------------------------------------------
  115. //
  116. // Function: void printUnicodeFromAddress
  117. //
  118. // Synopsis: Prints a UNICODE string given the address of the UNICODE_STRING
  119. //
  120. // Arguments: ul64Address The Address of the UNICODE_STRING structure
  121. //
  122. // Returns: <VOID>
  123. //
  124. // History: 04-05-2000 glennp Created
  125. //
  126. // Notes:
  127. //
  128. //----------------------------------------------------------------------------
  129. void printUnicodeFromAddress (TARGET_ADDRESS ul64Address)
  130. {
  131. TARGET_ADDRESS ul64TarBuffer;
  132. ULONG bufferOffset;
  133. ULONG lengthRead;
  134. ULONG ulInfo;
  135. USHORT usLength;
  136. PWCHAR buffer;
  137. ul64TarBuffer = 0;
  138. bufferOffset = 0;
  139. usLength = 0;
  140. buffer = NULL;
  141. GetFieldOffset ("UNICODE_STRING", "Buffer", &bufferOffset);
  142. ReadPtr (ul64Address + bufferOffset, &ul64TarBuffer);
  143. GetFieldValue (ul64Address, "UNICODE_STRING", "Length", usLength);
  144. buffer = LocalAlloc (LPTR, usLength + sizeof (UNICODE_NULL));
  145. if (buffer == NULL) {
  146. dprintf ("<Failed to Allocate Unicode String Buffer>");
  147. return;
  148. }
  149. if (usLength > 0) {
  150. lengthRead = 0;
  151. ulInfo = ReadMemory (ul64TarBuffer, buffer, usLength, &lengthRead);
  152. if ((!ulInfo) || (lengthRead != usLength)) {
  153. dprintf ("<Failed to Read Entire Unicode String>");
  154. }
  155. }
  156. buffer [usLength / 2] = 0;
  157. dprintf ("%ws", buffer);
  158. LocalFree(buffer);
  159. return;
  160. }
  161. //+---------------------------------------------------------------------------
  162. //
  163. // Function: ULONG lengthUnicodeFromAddress
  164. //
  165. // Synopsis: Get the Length (in bytes) of a UNICODE_STRING (NULL not included)
  166. //
  167. // Arguments: ul64Address The Address of the UNICODE_STRING structure
  168. //
  169. // Returns: Length of String in Bytes
  170. //
  171. // History: 03-27-2000 glennp Created
  172. //
  173. // Notes:
  174. //
  175. //----------------------------------------------------------------------------
  176. ULONG lengthUnicodeFromAddress (TARGET_ADDRESS ul64Address)
  177. {
  178. USHORT usLength;
  179. usLength = 0;
  180. GetFieldValue (ul64Address, "UNICODE_STRING", "Length", usLength);
  181. return ((ULONG) (usLength));
  182. }
  183. //+---------------------------------------------------------------------------
  184. //
  185. // Function: void printUnicodeFromStruct
  186. //
  187. // Synopsis: Prints a UNICODE string from an element in a structure
  188. //
  189. // Arguments: Address The Address of the structure containing the US
  190. // Type The Type of the structure containing the US
  191. // Field The name of the field in the structure
  192. // This must be a UNICODE_STRING substructure
  193. //
  194. // Returns: <VOID>
  195. //
  196. // History: 04-05-2000 glennp Created
  197. //
  198. // Notes:
  199. //
  200. //----------------------------------------------------------------------------
  201. void printUnicodeFromStruct (TARGET_ADDRESS Address, PCHAR Type, PCHAR Field)
  202. {
  203. ULONG ulUnicodeOffset;
  204. GetFieldOffset (Type, Field, &ulUnicodeOffset);
  205. printUnicodeFromAddress (Address + ulUnicodeOffset);
  206. return;
  207. }
  208. //+---------------------------------------------------------------------------
  209. //
  210. // Function: ULONG GetWmiTraceAlignment
  211. //
  212. // Synopsis: Determines the Alignment modulus for events on the target
  213. //
  214. // Arguments: <NONE>
  215. //
  216. // Returns: The Alignment (normally 8 bytes)
  217. //
  218. // History: 04-05-2000 glennp Created
  219. //
  220. // Notes:
  221. //
  222. //----------------------------------------------------------------------------
  223. ULONG GetWmiTraceAlignment (void)
  224. {
  225. ULONG ulInfo;
  226. ULONG ulBytesRead;
  227. UCHAR alignment;
  228. TARGET_ADDRESS tarAddress;
  229. alignment = 8; // Set Default
  230. tarAddress = GetExpression ("NT!WmiTraceAlignment");
  231. ulInfo = ReadMemory (tarAddress, &alignment, sizeof (UCHAR), &ulBytesRead);
  232. if ((!ulInfo) || (ulBytesRead != sizeof (UCHAR))) {
  233. dprintf ("Failed to Read Alignment.\n");
  234. }
  235. return ((ULONG) alignment);
  236. }
  237. //+---------------------------------------------------------------------------
  238. //
  239. // Function: TARGET_ADDRESS FindLoggerContextArray
  240. //
  241. // Synopsis: Determines the location and size of the LoggerContext Array
  242. //
  243. // Arguments: -> ElementCount The number of elements in the array put here
  244. //
  245. // Returns: Target Address of the LoggerContext Array
  246. //
  247. // History: 04-05-2000 glennp Created
  248. //
  249. // Notes: Returns 0 on error
  250. //
  251. //----------------------------------------------------------------------------
  252. TARGET_ADDRESS FindLoggerContextArray (PULONG ElementCount)
  253. {
  254. TARGET_ADDRESS address;
  255. ULONG pointerSize;
  256. ULONG arraySize;
  257. address = 0;
  258. pointerSize = GetTypeSize ("PVOID");
  259. if ((arraySize = GetTypeSize ("NT!WmipLoggerContext") / pointerSize) != 0) {
  260. // Post Windows 2000 Version
  261. address = GetExpression ("NT!WmipLoggerContext");
  262. } else {
  263. // Windows 2000 and Before
  264. ULONG ulOffset;
  265. address = GetExpression ("NT!WmipServiceDeviceObject");
  266. ReadPtr (address, &address);
  267. GetFieldOffset ("DEVICE_OBJECT", "DeviceExtension", &ulOffset);
  268. ReadPtr (address + ulOffset, &address);
  269. GetFieldOffset ("WMISERVDEVEXT", "LoggerContextTable", &ulOffset);
  270. // ulOffset = 0x50;
  271. address += ulOffset;
  272. arraySize = GetTypeSize ("WMISERVDEVEXT.LoggerContextTable") / pointerSize;
  273. // arraySize = 32;
  274. }
  275. *ElementCount = arraySize;
  276. return (address);
  277. }
  278. //+---------------------------------------------------------------------------
  279. //
  280. // Function: TARGET_ADDRESS FindLoggerContext
  281. //
  282. // Synopsis: Finds the Address of a specific LoggerContext
  283. //
  284. // Arguments: ulLoggerId Ordinal of the specific LoggerContext
  285. //
  286. // Returns: Target Address of the LoggerContext
  287. //
  288. // History: 04-05-2000 glennp Created
  289. //
  290. // Notes: Returns 0 on error
  291. //
  292. //----------------------------------------------------------------------------
  293. TARGET_ADDRESS FindLoggerContext (ULONG ulLoggerId)
  294. {
  295. TARGET_ADDRESS tarAddress;
  296. ULONG ulMaxLoggerId;
  297. tarAddress = FindLoggerContextArray (&ulMaxLoggerId);
  298. if (tarAddress == 0) {
  299. dprintf (" Unable to Access Logger Context Array\n");
  300. } else {
  301. if (ulLoggerId >= ulMaxLoggerId) {
  302. dprintf (" Logger Id TOO LARGE\n");
  303. } else {
  304. // tarAddress += GetTypeSize ("PWMI_LOGGER_CONTEXT") * ulLoggerId; //BUGBUG
  305. tarAddress += GetTypeSize ("PVOID") * ulLoggerId;
  306. ReadPointer (tarAddress, &tarAddress);
  307. if (tarAddress == 0) {
  308. dprintf (" LOGGER ID %2d NOT RUNNING PRESENTLY\n", ulLoggerId);
  309. }
  310. }
  311. }
  312. return (tarAddress);
  313. }
  314. //+---------------------------------------------------------------------------
  315. //
  316. // Function: wmiDefaultFilter
  317. //
  318. // Synopsis: Filter procedure for wmiTracing. Returns Key
  319. //
  320. // Arguments: Context Arbitrary context: not used
  321. // pstEvent -> to EventTrace
  322. //
  323. // Returns: Key
  324. //
  325. // History: 04-05-2000 glennp Created
  326. //
  327. // Notes:
  328. //
  329. //----------------------------------------------------------------------------
  330. ULONGLONG __cdecl wmiDefaultFilter (
  331. PVOID Context,
  332. const PEVENT_TRACE pstEvent
  333. )
  334. {
  335. union {
  336. LARGE_INTEGER TimeStamp;
  337. ULONGLONG Key;
  338. } Union;
  339. Union.TimeStamp = pstEvent->Header.TimeStamp;
  340. if (Union.Key == 0) Union.Key = 1;
  341. return (Union.Key);
  342. }
  343. //+---------------------------------------------------------------------------
  344. //
  345. // Function: wmiDefaultCompare
  346. //
  347. // Synopsis: Performs comparision of three keys
  348. //
  349. // Arguments: SortElement1 -> to "Left" sort element to compare
  350. // SortElement2 -> to "Right" sort element to compare
  351. //
  352. // Returns: -3,-2,-1, 0, +1,+2,+3 for LessThan, Equal, GreaterThan (Left X Right)
  353. //
  354. // History: 04-05-2000 glennp Created
  355. //
  356. // Notes: The first key, "SequenceNo", is compared in a manor that allows
  357. // wrapping around the 32 bit limit.
  358. // The last key, "Ordinal", cannot have equal values and the code
  359. // takes advantage of that fact. This implies that 0 can never be returned.
  360. //
  361. //----------------------------------------------------------------------------
  362. int __cdecl wmiDefaultCompare (
  363. const WMITRACING_KD_SORTENTRY *SortElementL,
  364. const WMITRACING_KD_SORTENTRY *SortElementR
  365. )
  366. {
  367. int iResult;
  368. ULONG SequenceNoL;
  369. ULONG SequenceNoR;
  370. SequenceNoL = SortElementL->SequenceNo;
  371. SequenceNoR = SortElementR->SequenceNo;
  372. if (SequenceNoL == SequenceNoR) {
  373. if (SortElementL->Keyll == SortElementR->Keyll) {
  374. iResult = (SortElementL->Ordinal < SortElementR->Ordinal) ? -1 : +1;
  375. } else {
  376. iResult = (SortElementL->Keyll < SortElementR->Keyll) ? -2 : +2;
  377. }
  378. } else {
  379. iResult = ((SequenceNoL - SequenceNoR) > 0x80000000) ? -3 : +3; // See Notes
  380. }
  381. return (iResult);
  382. }
  383. //+---------------------------------------------------------------------------
  384. //
  385. // Function: wmiDefaultOutput
  386. //
  387. // Synopsis: Output procedure for wmiTracing. Performs simple dprintf
  388. //
  389. // Arguments: Context Arbitrary context: point to head of MOF list
  390. // SortElement -> sort element describing this event. Not used.
  391. // pstEvent -> to EventTrace
  392. //
  393. // Returns: <void>
  394. //
  395. // History: 04-05-2000 glennp Created
  396. //
  397. // Notes:
  398. //
  399. //----------------------------------------------------------------------------
  400. void __cdecl wmiDefaultOutput (
  401. PVOID UserContext,
  402. PLIST_ENTRY GuidListHeadPtr,
  403. const WMITRACING_KD_SORTENTRY *SortEntry,
  404. const PEVENT_TRACE pstHeader
  405. )
  406. {
  407. WCHAR wcaOutputLine[4096];
  408. wcaOutputLine[0] = 0;
  409. if(g_fpFormatTraceEvent == NULL) {
  410. g_fpFormatTraceEvent = GetAddr(FormatTraceEventString);
  411. }
  412. if(g_fpFormatTraceEvent != NULL) {
  413. g_fpFormatTraceEvent (GuidListHeadPtr, (PEVENT_TRACE) pstHeader,
  414. (TCHAR *) wcaOutputLine, sizeof (wcaOutputLine),
  415. (TCHAR *) NULL);
  416. } else {
  417. return;
  418. }
  419. dprintf ("%s\n", wcaOutputLine);
  420. return;
  421. }
  422. //+---------------------------------------------------------------------------
  423. //
  424. // Function: wmiKdProcessLinkList
  425. //
  426. // Synopsis: Calls supplied Procedure for each element in a linked list
  427. //
  428. // Arguments: TarLinklistHeadAddress Target Address of Linklist Head
  429. // Procedure Procedure to call for each Buffer
  430. // Context Procedure Context (passthrough)
  431. // Length Size of the Buffer
  432. // Alignment Entry alignment in bytes
  433. // Source Enum specifying type of buffer
  434. // Offset Offset of LL entry in Buffer
  435. // Print Flag passed to Procedure
  436. //
  437. // Returns: Count of Buffers Processed
  438. //
  439. // History: 04-05-2000 glennp Created
  440. //
  441. // Notes:
  442. //
  443. //----------------------------------------------------------------------------
  444. ULONG wmiKdProcessLinkList (
  445. TARGET_ADDRESS TarLinklistHeadAddress,
  446. WMITRACING_KD_LISTENTRY_PROC Procedure,
  447. PVOID Context,
  448. ULONG Length,
  449. ULONG Alignment,
  450. WMI_BUFFER_SOURCE Source,
  451. ULONG Offset,
  452. ULONG Print
  453. )
  454. {
  455. ULONG ulBufferCount;
  456. TARGET_ADDRESS tarLinklistEntryAddress;
  457. ulBufferCount = 0;
  458. tarLinklistEntryAddress = TarLinklistHeadAddress;
  459. while (ReadPtr (tarLinklistEntryAddress, &tarLinklistEntryAddress), // NOTE COMMA!
  460. tarLinklistEntryAddress != TarLinklistHeadAddress) {
  461. if (CheckControlC()) break;
  462. ++ulBufferCount;
  463. if (Print) { dprintf ("%4d\b\b\b\b", ulBufferCount); }
  464. Procedure (Context, tarLinklistEntryAddress - Offset, Length, ~0, Alignment, Source);
  465. }
  466. return ulBufferCount;
  467. }
  468. //+---------------------------------------------------------------------------
  469. //
  470. // Function: VOID wmiDumpProc
  471. //
  472. // Synopsis: Procedure passed to wmiKdProcessBuffers() when dumping the
  473. // Buffers to the screen. Performs Buffer Header fixup and
  474. // then records sort keys for those entries that are selected.
  475. //
  476. // Arguments: Context -> to struct sttTraceContext. Used for 'static' memory
  477. // Buffer Target Address of WMI Event buffer to analyze
  478. // Length Length of the buffer (previous parameter)
  479. // Alignment Alignment used by WMI on target machine
  480. // Source Enum of: free, flush, transition, current buffer source
  481. //
  482. // Returns: <VOID>
  483. //
  484. // History: 04-05-2000 glennp Created
  485. //
  486. // Notes:
  487. //
  488. //----------------------------------------------------------------------------
  489. VOID wmiDumpProc
  490. ( PVOID Context
  491. , TARGET_ADDRESS Buffer
  492. , ULONG Length
  493. , ULONG CpuNo
  494. , ULONG Alignment
  495. , WMI_BUFFER_SOURCE Source
  496. )
  497. {
  498. ULONG size;
  499. ULONG offset;
  500. ULONG ulInfo;
  501. ULONG ulLengthRead;
  502. PUCHAR pBuffer;
  503. WMI_HEADER_TYPE headerType;
  504. WMIBUFFERINFO stBufferInfo;
  505. WMITRACING_KD_SORTENTRY* pstSortEntries = NULL;
  506. struct sttTraceContext *pstContext;
  507. // Cast Context
  508. pstContext = (struct sttTraceContext *) Context;
  509. // Allocate Buffer
  510. pBuffer = LocalAlloc (LPTR, Length);
  511. if (pBuffer == NULL) {
  512. dprintf ("Failed to Allocate Buffer.\n");
  513. return;
  514. }
  515. // Copy Buffer from Target machine
  516. ulLengthRead = 0;
  517. ulInfo = ReadMemory (Buffer, pBuffer, Length, &ulLengthRead);
  518. if ((!ulInfo) || (ulLengthRead != Length)) {
  519. dprintf ("Failed to Read (Entire?) Buffer.\n");
  520. }
  521. // Get Initial Offset and Fixup Header
  522. memset (&stBufferInfo, 0, sizeof (stBufferInfo));
  523. stBufferInfo.BufferSource = Source;
  524. stBufferInfo.Buffer = pBuffer;
  525. stBufferInfo.BufferSize = Length;
  526. stBufferInfo.Alignment = Alignment;
  527. stBufferInfo.ProcessorNumber = CpuNo;
  528. offset = WmiGetFirstTraceOffset (&stBufferInfo);
  529. // Inspect Each Event
  530. while ((headerType = WmiGetTraceHeader (pBuffer, offset, &size)) != WMIHT_NONE) {
  531. ULONGLONG ullKey;
  532. union {
  533. EVENT_TRACE stEvent;
  534. CHAR caEvent[4096];
  535. } u;
  536. if (CheckControlC()) break;
  537. // Get a consistant header
  538. ulInfo = WmiParseTraceEvent (pBuffer, offset, headerType, &u, sizeof (u));
  539. // Filter and maybe Add to Sort Q
  540. if ((ullKey = pstContext->Filter (pstContext, &u.stEvent)) != 0) {
  541. ULONG CurIndex;
  542. PWMI_CLIENT_CONTEXT pstClientContext;
  543. struct sttSortControl *pstSortControl;
  544. PWMITRACING_KD_SORTENTRY pstSortEntry;
  545. pstClientContext = (PWMI_CLIENT_CONTEXT) &u.stEvent.Header.ClientContext;
  546. pstSortControl = pstContext->pstSortControl;
  547. CurIndex = pstSortControl->CurEntries;
  548. if (CurIndex >= pstSortControl->MaxEntries) {
  549. pstSortControl->MaxEntries = pstSortControl->MaxEntries * 2 + 64;
  550. pstSortEntries =
  551. realloc (pstSortControl->pstSortEntries,
  552. sizeof (WMITRACING_KD_SORTENTRY) * (pstSortControl->MaxEntries));
  553. if (pstSortEntries == NULL) {
  554. dprintf ("Memory Allocation Failure\n");
  555. goto error;
  556. }
  557. pstSortControl->pstSortEntries = pstSortEntries;
  558. }
  559. pstSortEntry = &pstSortControl->pstSortEntries[CurIndex];
  560. memset (pstSortEntry, 0, sizeof (*pstSortEntry));
  561. pstSortEntry->Address = Buffer;
  562. pstSortEntry->Keyll = ullKey;
  563. { //BUGBUG: This code should be replaced after Ian/Melur supply a way to access SequenceNo
  564. PULONG pulEntry;
  565. pulEntry = (PULONG) &pBuffer[offset];
  566. if (((pulEntry[0] & 0xFF000000) == 0x90000000) &&
  567. ( pulEntry[1] & 0x00010000)) {
  568. pstSortEntry->SequenceNo = pulEntry[2];
  569. } else {
  570. pstSortEntry->SequenceNo = 0;
  571. }
  572. }
  573. pstSortEntry->Ordinal = pstContext->Ordinal++;
  574. pstSortEntry->Offset = offset;
  575. pstSortEntry->Length = size;
  576. pstSortEntry->BufferSource = Source;
  577. pstSortEntry->HeaderType = headerType;
  578. pstSortEntry->CpuNo = (USHORT) CpuNo;
  579. pstSortControl->CurEntries++;
  580. } // If passes Filtering
  581. size = ((size + (Alignment-1)) / Alignment) * Alignment; //BUGBUG: Need fix in GetTraceHeader or WmiFlush. Then remove this line.
  582. offset += size; // Move to next entry.
  583. }
  584. error:
  585. LocalFree (pBuffer);
  586. return;
  587. }
  588. //+---------------------------------------------------------------------------
  589. //
  590. // Function: ULONG wmiKdWriteFileHeader
  591. //
  592. // Synopsis: Write the file header when performing a Save command.
  593. //
  594. // Arguments: SaveFile Handle to a file where we will write the header
  595. // LoggerId Ordinal of the Stream we are writing the header for
  596. // TarLoggerContext TargetAddress of the LoggerContext
  597. //
  598. // Returns: <VOID>
  599. //
  600. // History: 04-05-2000 glennp Created
  601. //
  602. // Notes: This code should really be in wmi somewhere. It's here due to
  603. // the difficulty of creating a simply parameterized procedure.
  604. //
  605. //----------------------------------------------------------------------------
  606. ULONG
  607. wmiKdWriteFileHeader
  608. ( FILE *SaveFile
  609. , ULONG LoggerId
  610. , TARGET_ADDRESS TarLoggerContext
  611. )
  612. {
  613. ULONG ulInfo;
  614. ULONG ulBytesRead;
  615. ULONG ulAlignment;
  616. ULONG ulBufferSize;
  617. ULONG ulBufferCount;
  618. ULONG ulPointerSize;
  619. ULONG ulHeaderWritten;
  620. ULONG ulInstanceGuidOffset;
  621. UCHAR MajorVersion;
  622. UCHAR MinorVersion;
  623. PROCESSORINFO ProcessorInfo;
  624. PCHAR pcEnd;
  625. struct sttFileHeader {
  626. WMI_BUFFER_HEADER Buffer;
  627. SYSTEM_TRACE_HEADER Event;
  628. TRACE_LOGFILE_HEADER Header;
  629. WCHAR LogName[256]; //BUGBUG: Size??
  630. WCHAR FileName[256]; //BUGBUG: Size??
  631. } stFileHeader;
  632. ZeroMemory (&stFileHeader, sizeof (stFileHeader));
  633. ulAlignment = GetWmiTraceAlignment ();
  634. ulPointerSize = GetTypeSize ("PVOID");
  635. GetFieldOffset ("NT!_WMI_LOGGER_CONTEXT", "InstanceGuid", &ulInstanceGuidOffset);
  636. // Get ProcessorInfo and Kernel-User Shared Data
  637. Ioctl (IG_KD_CONTEXT, &ProcessorInfo, sizeof (ProcessorInfo));
  638. // Get Version Info
  639. if (!HaveDebuggerData ()) {
  640. dprintf ("No Version Information Available.");
  641. MajorVersion = MinorVersion = 0;
  642. } else {
  643. MajorVersion = (UCHAR) KernelVersionPacket.MajorVersion;
  644. MinorVersion = (UCHAR) KernelVersionPacket.MinorVersion;
  645. }
  646. // Get Infomation from LoggerContext on Target
  647. InitTypeRead (TarLoggerContext, NT!_WMI_LOGGER_CONTEXT);
  648. ulBufferSize = (ULONG) ReadField (BufferSize);
  649. ulBufferCount = (ULONG) ReadField (NumberOfBuffers);
  650. stFileHeader.Buffer.Wnode.BufferSize = ulBufferSize;
  651. stFileHeader.Buffer.ClientContext.LoggerId =
  652. (USHORT) ((LoggerId) ? LoggerId : KERNEL_LOGGER_ID);
  653. stFileHeader.Buffer.ClientContext.Alignment = (UCHAR) ulAlignment;
  654. ulInfo = ReadMemory (TarLoggerContext + ulInstanceGuidOffset,
  655. &stFileHeader.Buffer.Wnode.Guid,
  656. sizeof (stFileHeader.Buffer.Wnode.Guid),
  657. &ulBytesRead);
  658. if ((!ulInfo) || (ulBytesRead != sizeof (stFileHeader.Buffer.Wnode.Guid))) {
  659. dprintf ("Unable to Read Wnode.Guid\n");
  660. }
  661. stFileHeader.Buffer.Wnode.Flags = WNODE_FLAG_TRACED_GUID;
  662. ulInfo = ReadMemory (TarLoggerContext + ulInstanceGuidOffset,
  663. &stFileHeader.Buffer.InstanceGuid,
  664. sizeof (stFileHeader.Buffer.InstanceGuid),
  665. &ulBytesRead);
  666. if ((!ulInfo) || (ulBytesRead != sizeof (stFileHeader.Buffer.InstanceGuid))) {
  667. dprintf ("Unable to Read InstanceGuid\n");
  668. }
  669. // Single Event (File Header)
  670. stFileHeader.Event.Marker = TRACE_HEADER_FLAG | TRACE_HEADER_EVENT_TRACE |
  671. ((ulPointerSize > 4) ? (TRACE_HEADER_TYPE_SYSTEM64 << 16)
  672. : (TRACE_HEADER_TYPE_SYSTEM32 << 16));
  673. stFileHeader.Event.Packet.Group = (UCHAR) EVENT_TRACE_GROUP_HEADER >> 8;
  674. stFileHeader.Event.Packet.Type = EVENT_TRACE_TYPE_INFO;
  675. stFileHeader.Header.StartTime.QuadPart = ReadField (StartTime);
  676. stFileHeader.Header.BufferSize = ulBufferSize;
  677. stFileHeader.Header.VersionDetail.MajorVersion = MajorVersion;
  678. stFileHeader.Header.VersionDetail.MinorVersion = MinorVersion;
  679. //
  680. // The following #if 0's show fields in the header difficult to access from the debugger.
  681. //
  682. #if 0
  683. stFileHeader.Header.VersionDetail.SubVersion = TRACE_VERSION_MAJOR;
  684. stFileHeader.Header.VersionDetail.SubMinorVersion = TRACE_VERSION_MINOR;
  685. stFileHeader.Header.ProviderVersion = NtBuildNumber;
  686. #endif
  687. stFileHeader.Header.StartBuffers = 1;
  688. #if 0
  689. stFileHeader.Header.BootTime = KeBootTime;
  690. stFileHeader.Header.LogFileMode = LocLoggerContext.LogFileMode &
  691. (~(EVENT_TRACE_REAL_TIME_MODE | EVENT_TRACE_FILE_MODE_CIRCULAR));
  692. #endif
  693. stFileHeader.Header.NumberOfProcessors = ProcessorInfo.NumberProcessors;
  694. stFileHeader.Header.MaximumFileSize = (ULONG) ReadField (MaximumFileSize);
  695. #if 0
  696. KeQueryPerformanceCounter (&stFileHeader.Header.PerfFreq);
  697. if (WmiUsePerfClock) {
  698. stFileHeader.Header.ReservedFlags = 1;
  699. }
  700. stFileHeader.Header.TimerResolution = KeMaximumIncrement; // DO NOT CHANGE KDDEBUGGER_DATA32!!
  701. #endif
  702. #if 0
  703. stFileHeader.Header.LoggerName = (PWCHAR) ( ( (PUCHAR) ( &stFileHeader.Header ) ) +
  704. sizeof(TRACE_LOGFILE_HEADER) );
  705. stFileHeader.Header.LogFileName = (PWCHAR) ( (PUCHAR)stFileHeader.Header.LoggerName +
  706. LocLoggerContext.LoggerName.Length +
  707. sizeof(UNICODE_NULL));
  708. if (!ReadTargetMemory (LocLoggerContext.LoggerName.Buffer,
  709. stFileHeader.Header.LoggerName,
  710. LocLoggerContext.LoggerName.Length + sizeof(UNICODE_NULL)) ) {
  711. dprintf ("Can't access LoggerName (LoggerContext.LoggerName.Buffer) memory.\n");
  712. }
  713. MultiByteToWideChar (
  714. CP_OEMCP, 0,
  715. pszSaveFileName, -1,
  716. stFileHeader.Header.LogFileName, countof (stFileHeader.FileName));
  717. #if 0
  718. RtlQueryTimeZoneInformation(&stFileHeader.Header.TimeZone);
  719. stFileHeader.Header.EndTime;
  720. #endif
  721. #endif
  722. stFileHeader.Header.PointerSize = ulPointerSize;
  723. pcEnd = (PCHAR) &stFileHeader.LogName; //BUGBUG: Use Calculation Just Below
  724. #if 0
  725. pcEnd = ((PCHAR) stFileHeader.Header.LogFileName) +
  726. ((strlen (pszSaveFileName) + 1) * sizeof (WCHAR));
  727. stFileHeader.Buffer.Offset = (ULONG) (pcEnd - ((PCHAR) &stFileHeader));
  728. #endif
  729. stFileHeader.Event.Packet.Size = (USHORT) (pcEnd - ((PCHAR) &stFileHeader.Event));
  730. //
  731. // Fixup Lengths; Write out Header, 0xFF to length of buffer
  732. //
  733. ulHeaderWritten = (ULONG) (pcEnd - ((PCHAR) &stFileHeader));
  734. stFileHeader.Buffer.Offset = ulHeaderWritten;
  735. stFileHeader.Buffer.SavedOffset = ulHeaderWritten;
  736. stFileHeader.Buffer.CurrentOffset = ulHeaderWritten;
  737. fwrite (&stFileHeader, ulHeaderWritten, 1, SaveFile);
  738. while (ulHeaderWritten < ulBufferSize) {
  739. ULONG ulAllOnes;
  740. ULONG ulByteCount;
  741. ulAllOnes = ~((ULONG) 0);
  742. ulByteCount = ulBufferSize - ulHeaderWritten;
  743. if (ulByteCount > sizeof (ulAllOnes)) ulByteCount = sizeof (ulAllOnes);
  744. fwrite (&ulAllOnes, ulByteCount, 1, SaveFile);
  745. ulHeaderWritten += sizeof (ulAllOnes);
  746. }
  747. return (0);
  748. }
  749. //+---------------------------------------------------------------------------
  750. //
  751. // Function: VOID wmiSaveProc
  752. //
  753. // Synopsis: Procedure passed to wmiKdProcessBuffers() when saving the
  754. // Buffers to a file for later processing. Performs buffer
  755. // Header fixup and then writes the buffer to the file.
  756. //
  757. // Arguments: Context -> to struct sttSaveContext. Used for 'static' memory
  758. // Buffer Target Address of WMI Event buffer to save
  759. // Length Length of the buffer (previous parameter)
  760. // Alignment Alignment used by WMI on target machine
  761. // Source Enum of: free, flush, transition, current: buffer source
  762. //
  763. // Returns: <VOID>
  764. //
  765. // History: 04-05-2000 glennp Created
  766. //
  767. // Notes:
  768. //
  769. //----------------------------------------------------------------------------
  770. VOID wmiSaveProc
  771. ( PVOID Context
  772. , TARGET_ADDRESS Buffer
  773. , ULONG Length
  774. , ULONG CpuNo
  775. , ULONG Alignment
  776. , WMI_BUFFER_SOURCE Source
  777. )
  778. {
  779. ULONG ulInfo;
  780. ULONG ulLengthRead;
  781. PCHAR pBuffer;
  782. struct sttSaveContext *pstContext;
  783. WMIBUFFERINFO stBufferInfo;
  784. pstContext = (struct sttSaveContext *) Context;
  785. // Allocate Buffer
  786. pBuffer = LocalAlloc (LPTR, Length);
  787. if (pBuffer == NULL) {
  788. dprintf ("Failed to Allocate Buffer.\n");
  789. return;
  790. }
  791. // Read Buffer
  792. ulLengthRead = 0;
  793. ulInfo = ReadMemory (Buffer, pBuffer, Length, &ulLengthRead);
  794. if ((!ulInfo) || (ulLengthRead != Length)) {
  795. dprintf ("Failed to Read (Entire?) Buffer.\n");
  796. }
  797. // Fixup Buffer Header
  798. memset (&stBufferInfo, 0, sizeof (stBufferInfo));
  799. stBufferInfo.BufferSource = Source;
  800. stBufferInfo.Buffer = pBuffer;
  801. stBufferInfo.BufferSize = Length;
  802. stBufferInfo.ProcessorNumber = CpuNo;
  803. stBufferInfo.Alignment = Alignment;
  804. WmiGetFirstTraceOffset (&stBufferInfo);
  805. // Write to Log File
  806. ulInfo = fwrite (pBuffer, 1, Length, pstContext->pfSaveFile);
  807. if (ulInfo != Length) {
  808. dprintf ("Failed to Write Buffer.\n");
  809. }
  810. // Free Buffer, Return
  811. LocalFree (pBuffer);
  812. return;
  813. }
  814. //+---------------------------------------------------------------------------
  815. //
  816. // Function: ULONG wmiKdProcessNonblockingBuffers
  817. //
  818. // Synopsis: Calls Caller-Supplied Procedure for each Buffer in Locations/
  819. // Lists as specified by 'Sources'. Walks lists, Enumerates
  820. // CPU's buffers, and handles 'Transition Buffer' logic.
  821. //
  822. // Arguments: LoggerId
  823. // LoggerContext
  824. // Procedure
  825. // Context
  826. // Sources
  827. //
  828. // Returns: ULONG: Number of Buffers Processed
  829. //
  830. // History: 04-05-2000 glennp Created
  831. //
  832. // Notes: Sources also controls informational printing
  833. //
  834. //----------------------------------------------------------------------------
  835. ULONG
  836. wmiKdProcessNonblockingBuffers(
  837. ULONG LoggerId,
  838. TARGET_ADDRESS LoggerContext,
  839. WMITRACING_KD_LISTENTRY_PROC Procedure,
  840. PVOID Context,
  841. WMITRACING_BUFFER_SOURCES Sources
  842. )
  843. {
  844. TARGET_ADDRESS tarAddress;
  845. TARGET_ADDRESS tarBufferListPointer;
  846. ULONG pointerSize;
  847. PROCESSORINFO ProcessorInfo;
  848. ULONG ulOrdinal;
  849. ULONG ulAlignment;
  850. ULONG ulBufferSize;
  851. ULONG ulLoopCount;
  852. ULONG ulBufferCount;
  853. ULONG ulBufferNumber;
  854. ULONG tarBufferListOffset;
  855. // Get Pointer to Context Structure
  856. tarAddress = LoggerContext;
  857. if (tarAddress == 0) return (0);
  858. // Initialize Locals
  859. ulBufferNumber = 0;
  860. ulBufferCount = 0;
  861. ulLoopCount = 0;
  862. // Get Sizes, Offsets, Alignments from Target
  863. pointerSize = GetTypeSize ("PVOID");
  864. ulAlignment = GetWmiTraceAlignment ();
  865. GetFieldOffset ("NT!_WMI_BUFFER_HEADER", "GlobalEntry", &tarBufferListOffset);
  866. // Optionally Print LoggerId, Context Address, Logger name
  867. if (Sources.PrintInformation) {
  868. dprintf (" Logger Id %2d @ 0x%P Named '", LoggerId, tarAddress);
  869. printUnicodeFromStruct (tarAddress, "NT!_WMI_LOGGER_CONTEXT", "LoggerName");
  870. dprintf ("'\n");
  871. }
  872. // Setup ReadField's Context, Find Buffer Size
  873. InitTypeRead (tarAddress, NT!_WMI_LOGGER_CONTEXT);
  874. ulBufferSize = (ULONG) ReadField (BufferSize);
  875. // Optionally Print a few interesting numbers
  876. if (Sources.PrintInformation) {
  877. dprintf (" Alignment = %ld\n", ulAlignment);
  878. dprintf (" BufferSize = %ld\n", ulBufferSize);
  879. dprintf (" BufferCount = %ld\n", (ULONG) ReadField (NumberOfBuffers));
  880. dprintf (" MaximumBuffers = %ld\n", (ULONG) ReadField (MaximumBuffers));
  881. dprintf (" MinimumBuffers = %ld\n", (ULONG) ReadField (MinimumBuffers));
  882. dprintf (" EventsLost = %ld\n", (ULONG) ReadField (EventsLost));
  883. dprintf (" LogBuffersLost = %ld\n", (ULONG) ReadField (LogBuffersLost));
  884. dprintf (" RealTimeBuffersLost=%ld\n", (ULONG) ReadField (RealTimeBuffersLost));
  885. dprintf (" BuffersAvailable = %ld\n", (ULONG) ReadField (BuffersAvailable));
  886. dprintf (" LastFlushedBuffer = %ld\n", (ULONG) ReadField (LastFlushedBuffer));
  887. }
  888. dprintf (" Processing Global List: 0");
  889. tarBufferListPointer = 0;
  890. GetFieldValue (tarAddress, "NT!_WMI_LOGGER_CONTEXT", "GlobalList.Next", tarBufferListPointer);
  891. while (tarBufferListPointer != 0) {
  892. WMI_BUFFER_SOURCE source;
  893. ULONG ulCpuNumber;
  894. int iBufferUses;
  895. int iProcessBuffer;
  896. TARGET_ADDRESS tarBufferPointer;
  897. ULONG ulFree, ulInUse, ulFlush;
  898. iBufferUses = 0;
  899. ulCpuNumber = ~((ULONG) 0);
  900. iProcessBuffer = FALSE;
  901. source = WMIBS_TRANSITION_LIST;
  902. tarBufferPointer = tarBufferListPointer - tarBufferListOffset;
  903. dprintf ("\b\b\b%3d", ++ulLoopCount);
  904. InitTypeRead (tarBufferPointer, NT!_WMI_BUFFER_HEADER);
  905. ulFree = (ULONG) ReadField (State.Free);
  906. ulInUse = (ULONG) ReadField (State.InUse);
  907. ulFlush = (ULONG) ReadField (State.Flush);
  908. // Decide on Buffer Processing based on Use Flags and 'Sources'
  909. if (ulFree ) iBufferUses += 1;
  910. if (ulInUse) iBufferUses += 2;
  911. if (ulFlush) iBufferUses += 4;
  912. switch (iBufferUses) {
  913. case 0: { // No bits set, never used.
  914. break;
  915. }
  916. case 1: { // Free
  917. iProcessBuffer = Sources.FreeBuffers;
  918. source = WMIBS_FREE_LIST;
  919. break;
  920. }
  921. case 2: { // InUse
  922. iProcessBuffer = Sources.ActiveBuffers;
  923. source = WMIBS_CURRENT_LIST;
  924. //source = WMIBS_FLUSH_LIST;
  925. break;
  926. }
  927. case 3: { // MULTIPLE BITS SET, ERROR
  928. dprintf ("\n***Error, Inconsistent Flags Bits (Free,InUse) Set.***\n");
  929. break;
  930. }
  931. case 4: { // Flush
  932. iProcessBuffer = Sources.FlushBuffers;
  933. source = WMIBS_FLUSH_LIST;
  934. break;
  935. }
  936. case 5: {
  937. dprintf ("\n***Error, Inconsistent Flags Bits (Free,Flush) Set.***\n");
  938. break;
  939. }
  940. case 6: {
  941. dprintf ("\n***Error, Inconsistent Flags Bits (InUse,Flush) Set.***\n");
  942. break;
  943. }
  944. case 7: {
  945. dprintf ("\n***Error, Inconsistent Flags Bits (Free,InUse,Flush) Set.***\n");
  946. break;
  947. }
  948. }
  949. // ProcessBuffer as Decided Above
  950. if (iProcessBuffer) {
  951. ulBufferCount++;
  952. Procedure (Context, tarBufferPointer, ulBufferSize, ulCpuNumber, ulAlignment, source);
  953. }
  954. if (GetFieldValue (tarBufferPointer,
  955. "NT!_WMI_BUFFER_HEADER", "GlobalEntry",
  956. tarBufferListPointer) != 0) {
  957. dprintf ("\n***Error Following Global List.***\n");
  958. tarBufferListPointer = 0;
  959. }
  960. }
  961. dprintf (" Buffers\n");
  962. // Return w/ BufferCount
  963. return (ulBufferCount);
  964. } // wmiKdProcessNonblockingBuffers
  965. //+---------------------------------------------------------------------------
  966. //
  967. // Function: ULONG wmiKdProcessBlockingBuffers
  968. //
  969. // Synopsis: Calls Caller-Supplied Procedure for each Buffer in Locations/
  970. // Lists as specified by 'Sources'. Walks lists, Enumerates
  971. // CPU's buffers, and handles 'Transition Buffer' logic.
  972. //
  973. // Arguments: LoggerId
  974. // LoggerContext
  975. // Procedure
  976. // Context
  977. // Sources
  978. //
  979. // Returns: ULONG: Number of Buffers Processed
  980. //
  981. // History: 04-05-2000 glennp Created
  982. //
  983. // Notes: Sources also controls informational printing
  984. //
  985. //----------------------------------------------------------------------------
  986. ULONG
  987. wmiKdProcessBlockingBuffers(
  988. ULONG LoggerId,
  989. TARGET_ADDRESS LoggerContext,
  990. WMITRACING_KD_LISTENTRY_PROC Procedure,
  991. PVOID Context,
  992. WMITRACING_BUFFER_SOURCES Sources
  993. )
  994. {
  995. TARGET_ADDRESS tarAddress;
  996. ULONG pointerSize;
  997. PROCESSORINFO ProcessorInfo;
  998. ULONG ulOrdinal;
  999. ULONG ulAlignment;
  1000. ULONG ulBufferSize;
  1001. ULONG ulBufferCount;
  1002. ULONG ulBufferNumber;
  1003. ULONG ulBufferCountTotal;
  1004. ULONG tarFlushListOffset;
  1005. ULONG tarBufferListOffset;
  1006. // Get Pointer to Context Structure
  1007. tarAddress = LoggerContext;
  1008. if (tarAddress == 0) return (0);
  1009. // Initialize Locals
  1010. ulBufferNumber = 0;
  1011. ulBufferCount = 0;
  1012. ulBufferCountTotal = 0;
  1013. // Get Sizes, Offsets, Alignments from Target
  1014. pointerSize = GetTypeSize ("PVOID");
  1015. ulAlignment = GetWmiTraceAlignment ();
  1016. GetFieldOffset ("NT!_WMI_BUFFER_HEADER", "Entry", &tarBufferListOffset);
  1017. GetFieldOffset ("NT!_WMI_LOGGER_CONTEXT", "FlushList", &tarFlushListOffset);
  1018. // Optionally Print LoggerId, Context Address, Logger name
  1019. if (Sources.PrintInformation) {
  1020. dprintf (" Logger Id %2d @ 0x%P Named '", LoggerId, tarAddress);
  1021. printUnicodeFromStruct (tarAddress, "NT!_WMI_LOGGER_CONTEXT", "LoggerName");
  1022. dprintf ("'\n");
  1023. }
  1024. // Setup ReadField's Context, Find Buffer Size
  1025. InitTypeRead (tarAddress, NT!_WMI_LOGGER_CONTEXT);
  1026. ulBufferSize = (ULONG) ReadField (BufferSize);
  1027. // Optionally Print a few interesting numbers
  1028. if (Sources.PrintInformation) {
  1029. dprintf (" Alignment = %ld\n", ulAlignment);
  1030. dprintf (" BufferSize = %ld\n", ulBufferSize);
  1031. dprintf (" BufferCount = %ld\n", (ULONG) ReadField (NumberOfBuffers));
  1032. dprintf (" MaximumBuffers = %ld\n", (ULONG) ReadField (MaximumBuffers));
  1033. dprintf (" MinimumBuffers = %ld\n", (ULONG) ReadField (MinimumBuffers));
  1034. dprintf (" EventsLost = %ld\n", (ULONG) ReadField (EventsLost));
  1035. dprintf (" LogBuffersLost = %ld\n", (ULONG) ReadField (LogBuffersLost));
  1036. dprintf (" RealTimeBuffersLost=%ld\n", (ULONG) ReadField (RealTimeBuffersLost));
  1037. dprintf (" BuffersAvailable = %ld\n", (ULONG) ReadField (BuffersAvailable));
  1038. dprintf (" LastFlushedBuffer = %ld\n", (ULONG) ReadField (LastFlushedBuffer));
  1039. }
  1040. // Setup for Checks against TransitionBuffer Address IF REQUESTED
  1041. TransitionBuffer = 0;
  1042. if (Sources.TransitionBuffer) {
  1043. TARGET_ADDRESS tarTransitionBuffer;
  1044. tarTransitionBuffer = ReadField (TransitionBuffer);
  1045. if ((tarTransitionBuffer != 0) &&
  1046. (tarTransitionBuffer != (tarAddress + tarFlushListOffset))) {
  1047. ULONG tarTransitionBufferOffset;
  1048. GetFieldOffset ("NT!_WMI_BUFFER_HEADER", "Entry", &tarTransitionBufferOffset);
  1049. tarTransitionBuffer = tarAddress - tarTransitionBufferOffset;
  1050. TransitionBuffer = tarTransitionBuffer;
  1051. }
  1052. }
  1053. // Access the Free Queue Buffers IF REQUESTED
  1054. if (Sources.FreeBuffers) {
  1055. ULONG tarFreeListOffset;
  1056. GetFieldOffset ("NT!_WMI_LOGGER_CONTEXT", "FreeList", &tarFreeListOffset);
  1057. dprintf (" Processing FreeQueue: ");
  1058. ulBufferCount = wmiKdProcessLinkList (tarAddress + tarFreeListOffset,
  1059. Procedure, Context, ulBufferSize, ulAlignment, WMIBS_FREE_LIST,
  1060. tarBufferListOffset, Sources.PrintProgressIndicator);
  1061. dprintf ("%ld Buffers\n", ulBufferCount);
  1062. ulBufferCountTotal += ulBufferCount;
  1063. }
  1064. // Access the Flush Queue Buffers IF REQUESTED
  1065. if (Sources.FlushBuffers) {
  1066. dprintf (" Processing FlushQueue: ");
  1067. ulBufferCount = wmiKdProcessLinkList (tarAddress + tarFlushListOffset,
  1068. Procedure, Context, ulBufferSize, ulAlignment, WMIBS_FLUSH_LIST,
  1069. tarBufferListOffset, Sources.PrintProgressIndicator);
  1070. dprintf ("%ld Buffers\n", ulBufferCount);
  1071. ulBufferCountTotal += ulBufferCount;
  1072. }
  1073. // Access the 'Live' buffers (one per cpu) IF REQUESTED
  1074. if (Sources.ActiveBuffers) {
  1075. TARGET_ADDRESS tarProcessorArrayAddress;
  1076. GetFieldValue (tarAddress,"NT!_WMI_LOGGER_CONTEXT", "ProcessorBuffers", tarProcessorArrayAddress);
  1077. Ioctl (IG_KD_CONTEXT, &ProcessorInfo, sizeof (ProcessorInfo));
  1078. for (ProcessorInfo.Processor = 0;
  1079. ProcessorInfo.Processor < ProcessorInfo.NumberProcessors;
  1080. ++ProcessorInfo.Processor) {
  1081. TARGET_ADDRESS tarProcessorPointer;
  1082. ReadPtr (tarProcessorArrayAddress + ProcessorInfo.Processor * pointerSize,
  1083. &tarProcessorPointer);
  1084. dprintf (" Cpu %d Buffer Header @ 0x%P ",
  1085. ProcessorInfo.Processor, tarProcessorPointer);
  1086. Procedure (Context, tarProcessorPointer, ulBufferSize,
  1087. ProcessorInfo.Processor, ulAlignment, WMIBS_CURRENT_LIST);
  1088. ulBufferCountTotal += 1;
  1089. dprintf (" \b\n");
  1090. } // Cpu Loop
  1091. }
  1092. // Process the Transition Entry (if any). Note 'IF REQUESTED' test above in Setup
  1093. if (TransitionBuffer != 0) {
  1094. dprintf (" Transition Buffer @ 0x%P ", TransitionBuffer);
  1095. Procedure (Context, TransitionBuffer, ulBufferSize, ~0, ulAlignment, WMIBS_TRANSITION_LIST);
  1096. ulBufferCountTotal += 1;
  1097. }
  1098. // Return w/ BufferCount
  1099. return (ulBufferCountTotal);
  1100. } // wmiKdProcessBlockingBuffers
  1101. //+---------------------------------------------------------------------------
  1102. //
  1103. // Function: ULONG wmiKdProcessBuffers
  1104. //
  1105. // Synopsis: Decides if the target system is using doubly-linked (blocking)
  1106. // or singly-linked (non-blocking) lists of buffers. Then it
  1107. // calls the appropriate Buffer-Walking routine. They:
  1108. // Call Caller-Supplied Procedure for each Buffer in Locations/
  1109. // Lists as specified by 'Sources'. Walk lists, Enumerates
  1110. // CPU's buffers, and handles 'Transition Buffer' logic.
  1111. //
  1112. // Arguments: LoggerId
  1113. // LoggerContext
  1114. // Procedure
  1115. // Context
  1116. // Sources
  1117. //
  1118. // Returns: ULONG: Number of Buffers Processed
  1119. //
  1120. // History: 04-05-2000 glennp Created
  1121. //
  1122. // Notes: Sources also controls informational printing
  1123. //
  1124. //----------------------------------------------------------------------------
  1125. ULONG
  1126. wmiKdProcessBuffers(
  1127. ULONG LoggerId,
  1128. TARGET_ADDRESS LoggerContext,
  1129. WMITRACING_KD_LISTENTRY_PROC Procedure,
  1130. PVOID Context,
  1131. WMITRACING_BUFFER_SOURCES Sources
  1132. )
  1133. {
  1134. ULONG ulBufferCountTotal;
  1135. int iBufferMechanism;
  1136. ULONG tarGlobalListOffset;
  1137. ULONG tarTransitionBufferOffset;
  1138. iBufferMechanism = 0;
  1139. ulBufferCountTotal = 0;
  1140. if ((GetFieldOffset ("NT!_WMI_LOGGER_CONTEXT", "GlobalList", &tarGlobalListOffset) == 0) &&
  1141. (tarGlobalListOffset != 0)) {
  1142. iBufferMechanism += 1;
  1143. }
  1144. if ((GetFieldOffset ("NT!_WMI_LOGGER_CONTEXT", "TransitionBuffer", &tarTransitionBufferOffset) == 0) &&
  1145. (tarTransitionBufferOffset != 0)) {
  1146. iBufferMechanism += 2;
  1147. }
  1148. switch (iBufferMechanism) {
  1149. case 0: { // Neither, ???
  1150. dprintf ("Unable to determine buffer mechanism. "
  1151. "Check for complete symbol availability.\n");
  1152. break;
  1153. }
  1154. case 1: { // Global, no Transition
  1155. ulBufferCountTotal = wmiKdProcessNonblockingBuffers (LoggerId, LoggerContext,
  1156. Procedure, Context, Sources);
  1157. break;
  1158. }
  1159. case 2: { // Transition, no Global
  1160. ulBufferCountTotal = wmiKdProcessBlockingBuffers (LoggerId, LoggerContext,
  1161. Procedure, Context, Sources);
  1162. break;
  1163. }
  1164. case 3: { // Both, ???
  1165. dprintf ("Unable to determine buffer mechanism. "
  1166. "Check for new wmiTrace debugger extension. GO = %d, TB = %d\n",
  1167. tarGlobalListOffset, tarTransitionBufferOffset);
  1168. break;
  1169. }
  1170. }
  1171. // Return w/ BufferCount
  1172. return (ulBufferCountTotal);
  1173. } // wmiKdProcessBuffers
  1174. //+---------------------------------------------------------------------------
  1175. //
  1176. // Function: VOID wmiLogDump
  1177. //
  1178. // Synopsis: callable procedure to dump the in-memory part of a tracelog.
  1179. // Caller can supply three procedures to:
  1180. // 1. Filter and Select the Sort Key for VMI Events,
  1181. // 2. Compare the Sort Keys, and
  1182. // 3. Print the Output for each Selected Event.
  1183. // this procedure is called by the built-in extension logdump.
  1184. //
  1185. // Arguments: LoggerId -> the Id of the logger stream to process
  1186. // Context <OMITTED>
  1187. // GuidListHeadPtr -> to a list of MOF Guids from GetTraceGuids
  1188. // Filter -> to a replacement Filter procedure
  1189. // Compare -> to a replacement Compare (for Sort) procedure
  1190. // Output -> to a replacement Output procedure
  1191. //
  1192. // Returns: VOID
  1193. //
  1194. // History: 04-05-2000 glennp Created
  1195. //
  1196. //----------------------------------------------------------------------------
  1197. VOID wmiLogDump(
  1198. ULONG LoggerId,
  1199. PVOID UserContext,
  1200. PLIST_ENTRY GuidListHeadPtr,
  1201. WMITRACING_KD_FILTER Filter,
  1202. WMITRACING_KD_COMPARE Compare,
  1203. WMITRACING_KD_OUTPUT Output
  1204. )
  1205. {
  1206. ULONG ulOrdinal;
  1207. ULONG ulSortIndex;
  1208. ULONG ulBufferSize;
  1209. ULONG ulBufferCountTotal;
  1210. ULONG ulAlignment;
  1211. TARGET_ADDRESS tarAddress;
  1212. PCHAR locBufferAddress;
  1213. TARGET_ADDRESS lastBufferAddress;
  1214. struct sttSortControl stSortControl;
  1215. struct sttTraceContext stTraceContext;
  1216. WMITRACING_BUFFER_SOURCES stSources;
  1217. // Replace NULL procedures w/ defaults
  1218. if (Filter == NULL) Filter = wmiDefaultFilter;
  1219. if (Compare == NULL) Compare = wmiDefaultCompare;
  1220. if (Output == NULL) Output = wmiDefaultOutput;
  1221. // Initialize Locals
  1222. memset (&stSortControl, 0, sizeof (stSortControl));
  1223. memset (&stTraceContext, 0, sizeof (stTraceContext));
  1224. stTraceContext.pstSortControl = &stSortControl;
  1225. stTraceContext.UserContext = UserContext;
  1226. //stTraceContext.Ordinal = 0;
  1227. stTraceContext.Filter = Filter;
  1228. // Select (All) Sources
  1229. stSources.FreeBuffers = 1;
  1230. stSources.FlushBuffers = 1;
  1231. stSources.ActiveBuffers = 1;
  1232. stSources.TransitionBuffer = 1;
  1233. // Print Summary and ProgressIndicator
  1234. stSources.PrintInformation = 1;
  1235. stSources.PrintProgressIndicator = 1;
  1236. // Print Intro Message
  1237. dprintf ("(WmiTrace)LogDump for Log Id %ld\n", LoggerId);
  1238. // Get Pointer to Logger Context
  1239. tarAddress = FindLoggerContext (LoggerId);
  1240. ulAlignment = GetWmiTraceAlignment ();
  1241. // Filter and Gather all Messages we want
  1242. ulBufferCountTotal = wmiKdProcessBuffers (LoggerId, tarAddress,
  1243. wmiDumpProc, &stTraceContext, stSources);
  1244. // Sort the Entries just Gathered
  1245. qsort (stSortControl.pstSortEntries, stSortControl.CurEntries,
  1246. sizeof (stSortControl.pstSortEntries[0]), Compare);
  1247. if (stSortControl.CurEntries > 0) {
  1248. dprintf ("LOGGED MESSAGES (%ld):\n", stSortControl.CurEntries);
  1249. }
  1250. // Allocate Buffer
  1251. GetFieldValue (tarAddress, "NT!_WMI_LOGGER_CONTEXT", "BufferSize", ulBufferSize);
  1252. lastBufferAddress = 0; // For the buffer 'cache' (one item for now)
  1253. locBufferAddress = LocalAlloc (LPTR, ulBufferSize);
  1254. if (locBufferAddress == NULL) {
  1255. dprintf ("FAILED TO ALLOCATE NEEDED BUFFER!\n");
  1256. goto Cleanup;
  1257. }
  1258. // Print each (Sorted) Entry
  1259. for (ulSortIndex = 0; ulSortIndex < stSortControl.CurEntries; ++ulSortIndex) {
  1260. const WMITRACING_KD_SORTENTRY *sortEntry;
  1261. union {
  1262. EVENT_TRACE stEvent;
  1263. CHAR caEvent[4096];
  1264. } u;
  1265. if (CheckControlC()) break;
  1266. sortEntry = &stSortControl.pstSortEntries[ulSortIndex];
  1267. // Read the entire buffer if not same as last
  1268. if (lastBufferAddress != sortEntry->Address) {
  1269. {
  1270. ULONG ulInfo;
  1271. ULONG ulBytesRead;
  1272. // Read Buffer
  1273. ulBytesRead = 0;
  1274. lastBufferAddress = sortEntry->Address;
  1275. ulInfo =
  1276. ReadMemory (lastBufferAddress, locBufferAddress, ulBufferSize, &ulBytesRead);
  1277. if ((!ulInfo) || (ulBytesRead != ulBufferSize)) {
  1278. dprintf ("Failed to (Re)Read Buffer @ %P.\n", lastBufferAddress);
  1279. continue; // Try for others
  1280. }
  1281. }
  1282. {
  1283. WMIBUFFERINFO stBufferInfo;
  1284. // Perform Fixup
  1285. memset (&stBufferInfo, 0, sizeof (stBufferInfo));
  1286. stBufferInfo.BufferSource = sortEntry->BufferSource;
  1287. stBufferInfo.Buffer = locBufferAddress;
  1288. stBufferInfo.BufferSize = ulBufferSize;
  1289. stBufferInfo.ProcessorNumber = sortEntry->CpuNo;
  1290. stBufferInfo.Alignment = ulAlignment;
  1291. WmiGetFirstTraceOffset (&stBufferInfo);
  1292. }
  1293. }
  1294. // Get a consistant header
  1295. WmiParseTraceEvent (locBufferAddress, sortEntry->Offset, sortEntry->HeaderType,
  1296. &u, sizeof (u));
  1297. // Output the Entry
  1298. Output (UserContext, GuidListHeadPtr, sortEntry, &u.stEvent);
  1299. }
  1300. Cleanup:
  1301. // Free Buffer
  1302. LocalFree (locBufferAddress);
  1303. // Print Summary
  1304. dprintf ("Total of %ld Messages from %ld Buffers\n",
  1305. stSortControl.CurEntries,
  1306. ulBufferCountTotal);
  1307. // Free the sort elements (pointers + keys)
  1308. free (stSortControl.pstSortEntries);
  1309. return;
  1310. } // wmiLogDump
  1311. //+---------------------------------------------------------------------------
  1312. //
  1313. // Function: DECLARE_API(help)
  1314. //
  1315. // Synopsis: list available functions and syntax
  1316. //
  1317. // Arguments: <NONE>
  1318. //
  1319. // Returns: <VOID>
  1320. //
  1321. // History: 2-17-2000 glennp Created
  1322. //
  1323. // Notes:
  1324. //
  1325. //----------------------------------------------------------------------------
  1326. DECLARE_API( help )
  1327. {
  1328. dprintf("WMI Tracing Kernel Debugger Extensions\n");
  1329. dprintf(" logdump <LoggerId> [<guid file name>] - Dump the in-memory portion of a log file\n");
  1330. dprintf(" logsave <LoggerId> <Save file name> - Save the in-memory portion of a log file in binary form\n");
  1331. dprintf(" strdump [<LoggerId>] - Dump the Wmi Trace Event Structures\n");
  1332. dprintf(" searchpath <Path> - Set the trace format search path\n");
  1333. dprintf(" guidfile <filename> - Set the guid file name (default is 'default.tmf')\n");
  1334. dprintf(" dynamicprint <0|1> - Turn live tracing messages on (1) or off (0). Default is on.\n");
  1335. //dprintf(" kdtracing <LoggerId> <0|1> - Turn live tracing messages on (1) or off (0) for a particular logger.\n");
  1336. }
  1337. //+---------------------------------------------------------------------------
  1338. //
  1339. // Function: DECLARE_API(logdump)
  1340. //
  1341. // Synopsis: LOG DUMP: Dumps Trace Messages from a Log Stream to Stdout
  1342. //
  1343. // Arguments: <Stream Number> [<MofData.Guid File Name>]
  1344. //
  1345. // Returns: <VOID>
  1346. //
  1347. // History: 2-17-2000 glennp Created
  1348. //
  1349. // Notes:
  1350. //
  1351. //----------------------------------------------------------------------------
  1352. DECLARE_API( logdump )
  1353. {
  1354. ULONG_PTR ulStatus = 0;
  1355. // TARGET_ADDRESS tarAddress = NULL;
  1356. ULONG ulLoggerId;
  1357. const CHAR *argPtr = NULL;
  1358. size_t sztLen = 0;
  1359. // Defaults
  1360. ulLoggerId = 1;
  1361. // LoggerId ?
  1362. if (args && args[0]) {
  1363. ulLoggerId = (ULONG) GetExpression (args);
  1364. }
  1365. // LoggerId ?
  1366. argPtr = args + strspn (args, " \t\n");
  1367. sztLen = strspn (argPtr, "0123456789");
  1368. if (sztLen > 0) {
  1369. // ulLoggerId = atol (argPtr);
  1370. argPtr += sztLen;
  1371. }
  1372. // Guid Definition File
  1373. argPtr = argPtr + strspn (argPtr, " \t\n,");
  1374. if (strlen (argPtr)) {
  1375. //only change name if it is different from what is already stored
  1376. if(_stricmp(argPtr, g_pszGuidFileName)){
  1377. sztLen = strcspn (argPtr, " \t\n,");
  1378. //make sure name will not overrun buffer
  1379. if(sztLen >= MAX_PATH) {
  1380. sztLen = MAX_PATH - 1;
  1381. }
  1382. // lpFileName = (LPTSTR)malloc((sztLen + 1) * sizeof(TCHAR));
  1383. memcpy(g_pszGuidFileName, argPtr, sztLen);
  1384. g_pszGuidFileName[sztLen] = '\000';
  1385. if(g_GuidListHeadPtr != NULL) {
  1386. if(g_fpCleanupTraceEventList == NULL) {
  1387. g_fpCleanupTraceEventList = GetAddr("CleanupTraceEventList");
  1388. }
  1389. if(g_fpCleanupTraceEventList != NULL) {
  1390. g_fpCleanupTraceEventList (g_GuidListHeadPtr);
  1391. g_GuidListHeadPtr = NULL;
  1392. } else {
  1393. dprintf ("ERROR: Failed to clean up Guid list.\n");
  1394. return;
  1395. }
  1396. }
  1397. }
  1398. }
  1399. // Show LoggerId, FileName
  1400. dprintf ("WMI Generic Trace Dump: Debugger Extension. LoggerId = %ld, Guidfile = '%s'\n",
  1401. ulLoggerId, g_pszGuidFileName);
  1402. // Open Guid File, Dump Log, Cleanup
  1403. if(g_GuidListHeadPtr == NULL) {
  1404. if(g_fpGetTraceGuids == NULL) {
  1405. g_fpGetTraceGuids = GetAddr(GetTraceGuidsString);
  1406. }
  1407. if(g_fpGetTraceGuids != NULL) {
  1408. ulStatus = g_fpGetTraceGuids ((TCHAR *) g_pszGuidFileName, &g_GuidListHeadPtr);
  1409. }
  1410. if (ulStatus == 0) {
  1411. dprintf ("Failed to open Guid file '%hs'\n", g_pszGuidFileName);
  1412. return;
  1413. }
  1414. }
  1415. dprintf ("Opened Guid File '%hs' with %d Entries.\n",
  1416. g_pszGuidFileName, ulStatus);
  1417. wmiLogDump (ulLoggerId, NULL, g_GuidListHeadPtr, NULL, NULL, NULL);
  1418. /*if(g_fpCleanupTraceEventList == NULL) {
  1419. g_fpCleanupTraceEventList = GetAddr("CleanupTraceEventList");
  1420. }
  1421. if(g_fpCleanupTraceEventList != NULL) {
  1422. g_fpCleanupTraceEventList (g_GuidListHeadPtr);
  1423. g_GuidListHeadPtr = NULL;
  1424. }*/
  1425. return;
  1426. } // logdump
  1427. //+---------------------------------------------------------------------------
  1428. //
  1429. // Function: DECLARE_API(logsave)
  1430. //
  1431. // Synopsis: LOG DUMP: Dumps Trace Messages from a Log Stream to Stdout
  1432. //
  1433. // Arguments: <Stream Number> [<MofData.Guid File Name>]
  1434. //
  1435. // Returns: <VOID>
  1436. //
  1437. // History: 2-17-2000 glennp Created
  1438. //
  1439. // Notes:
  1440. //
  1441. //----------------------------------------------------------------------------
  1442. DECLARE_API( logsave )
  1443. {
  1444. ULONG ulStatus;
  1445. TARGET_ADDRESS tarAddress;
  1446. ULONG ulLoggerId;
  1447. LPSTR pszSaveFileName;
  1448. const CHAR *argPtr;
  1449. size_t sztLen;
  1450. CHAR caFileName[256];
  1451. // Defaults
  1452. ulLoggerId = 1;
  1453. pszSaveFileName = "LogData.elg";
  1454. // LoggerId ?
  1455. if (args && args[0]) {
  1456. ulLoggerId = (ULONG) GetExpression (args);
  1457. }
  1458. // Point beyond LoggerId
  1459. argPtr = args + strspn (args, " \t\n");
  1460. argPtr += strspn (argPtr, "0123456789");
  1461. // Save File
  1462. argPtr = argPtr + strspn (argPtr, " \t\n,");
  1463. if (strlen (argPtr)) {
  1464. sztLen = strcspn (argPtr, " \t\n,");
  1465. memcpy (caFileName, argPtr, sztLen);
  1466. caFileName[sztLen] = '\000';
  1467. pszSaveFileName = caFileName;
  1468. }
  1469. // Show LoggerId, FileName
  1470. dprintf ("WMI Trace Save: Debugger Extension. LoggerId = %ld, Save File = '%s'\n",
  1471. ulLoggerId, pszSaveFileName);
  1472. // Get Pointer to Logger Context
  1473. tarAddress = FindLoggerContext (ulLoggerId);
  1474. // Check if LoggerId Good
  1475. if (tarAddress == 0) {
  1476. dprintf ("Failed to Find Logger\n");
  1477. } else {
  1478. FILE *pfSaveFile;
  1479. // Open Guid File, Dump Log, Cleanup
  1480. pfSaveFile = fopen (pszSaveFileName, "ab");
  1481. if (pfSaveFile == NULL) {
  1482. dprintf ("Failed to Open Save File '%hs'\n", pszSaveFileName);
  1483. } else {
  1484. WMITRACING_BUFFER_SOURCES stSources;
  1485. struct sttSaveContext stSaveContext;
  1486. ULONG ulTotalBufferCount;
  1487. ULONG ulRealTime;
  1488. // See if we are in "RealTime" mode (if so, we'll save FreeBuffers too)
  1489. if (GetFieldValue (tarAddress,
  1490. "NT!_WMI_LOGGER_CONTEXT",
  1491. "LoggerModeFlags.RealTime",
  1492. ulRealTime)) {
  1493. dprintf ("Unable to Retrieve 'RealTime' Flag. Assuming Realtime Mode.\n");
  1494. ulRealTime = 1; // Better to get too many than too few.
  1495. }
  1496. //Write Header
  1497. wmiKdWriteFileHeader (pfSaveFile, ulLoggerId, tarAddress);
  1498. // Select Sources
  1499. stSources.FreeBuffers = (ulRealTime) ? 1 : 0;
  1500. stSources.FlushBuffers = 1;
  1501. stSources.ActiveBuffers = 1;
  1502. stSources.TransitionBuffer = 1;
  1503. stSources.PrintInformation = 1;
  1504. stSources.PrintProgressIndicator = 1;
  1505. // Setup SaveContext
  1506. stSaveContext.pfSaveFile = pfSaveFile;
  1507. // Write Buffers
  1508. ulTotalBufferCount = wmiKdProcessBuffers (ulLoggerId, tarAddress,
  1509. wmiSaveProc, &stSaveContext, stSources);
  1510. dprintf ("Saved %d Buffers\n", ulTotalBufferCount);
  1511. // Close
  1512. fclose (pfSaveFile);
  1513. }
  1514. }
  1515. return;
  1516. } // logdump
  1517. //+---------------------------------------------------------------------------
  1518. //
  1519. // Function: DECLARE_API(strdump)
  1520. //
  1521. // Synopsis: STRucture DUMP: dumps generic info (no arg) or stream info (arg)
  1522. //
  1523. // Arguments: [<Stream Number>]
  1524. //
  1525. // Returns: <VOID>
  1526. //
  1527. // History: 2-17-2000 glennp Created
  1528. //
  1529. // Notes:
  1530. //
  1531. //----------------------------------------------------------------------------
  1532. DECLARE_API( strdump )
  1533. /*
  1534. * dump the structures for trace logging
  1535. * strdump [<LoggerId>]
  1536. * If <LoggerId> present, dump structs for that Id
  1537. * Else dump generic structs
  1538. */
  1539. {
  1540. TARGET_ADDRESS tarAddress;
  1541. DWORD dwRead, Flags;
  1542. ULONG ulLoggerId;
  1543. ULONG ulMaxLoggerId;
  1544. ULONG pointerSize;
  1545. // Defaults
  1546. ulLoggerId = ~0;
  1547. pointerSize = GetTypeSize ("PVOID");
  1548. // LoggerId ?
  1549. if (args && args[0]) {
  1550. ulLoggerId = (ULONG) GetExpression (args);
  1551. }
  1552. if (ulLoggerId == ~0) {
  1553. dprintf ("(WmiTracing)StrDump Generic\n");
  1554. tarAddress = FindLoggerContextArray (&ulMaxLoggerId);
  1555. dprintf (" LoggerContext Array @ 0x%P [%d Elements]\n",
  1556. tarAddress, ulMaxLoggerId);
  1557. if (tarAddress) {
  1558. for (ulLoggerId = 0; ulLoggerId < ulMaxLoggerId; ++ulLoggerId) {
  1559. TARGET_ADDRESS contextAddress;
  1560. contextAddress = tarAddress + pointerSize * ulLoggerId;
  1561. /*if (*/ReadPointer (contextAddress, &contextAddress)/*) {*/;
  1562. //dprintf ("UNABLE TO READ POINTER in ARRAY of POINTERS!, Addr = 0x%P\n", contextAddress);
  1563. /*} else*/ if (contextAddress != 0) {
  1564. dprintf (" Logger Id %2d @ 0x%P Named '", ulLoggerId, contextAddress);
  1565. printUnicodeFromStruct (contextAddress, "NT!_WMI_LOGGER_CONTEXT", "LoggerName");
  1566. dprintf ("'\n");
  1567. }
  1568. }
  1569. }
  1570. } else {
  1571. dprintf ("(WmiTracing)StrDump for Log Id %ld\n", ulLoggerId);
  1572. tarAddress = FindLoggerContext (ulLoggerId);
  1573. if (tarAddress != 0) {
  1574. dprintf (" Logger Id %2d @ 0x%P Named '", ulLoggerId, tarAddress);
  1575. printUnicodeFromStruct (tarAddress, "NT!_WMI_LOGGER_CONTEXT", "LoggerName");
  1576. dprintf ("'\n");
  1577. InitTypeRead (tarAddress, NT!_WMI_LOGGER_CONTEXT);
  1578. dprintf (" BufferSize = %ld\n", (ULONG) ReadField (BufferSize));
  1579. dprintf (" BufferCount = %ld\n", (ULONG) ReadField (NumberOfBuffers));
  1580. dprintf (" MaximumBuffers = %ld\n", (ULONG) ReadField (MaximumBuffers));
  1581. dprintf (" MinimumBuffers = %ld\n", (ULONG) ReadField (MinimumBuffers));
  1582. dprintf (" EventsLost = %ld\n", (ULONG) ReadField (EventsLost));
  1583. dprintf (" LogBuffersLost = %ld\n", (ULONG) ReadField (LogBuffersLost));
  1584. dprintf (" RealTimeBuffersLost=%ld\n", (ULONG) ReadField (RealTimeBuffersLost));
  1585. dprintf (" BuffersAvailable = %ld\n", (ULONG) ReadField (BuffersAvailable));
  1586. dprintf (" LastFlushedBuffer = %ld\n", (ULONG) ReadField (LastFlushedBuffer));
  1587. dprintf (" LoggerId = 0x%02lX\n", (ULONG) ReadField (LoggerId));
  1588. dprintf (" CollectionOn = %ld\n", (ULONG) ReadField (CollectionOn));
  1589. dprintf (" KernelTraceOn = %ld\n", (ULONG) ReadField (KernelTraceOn));
  1590. dprintf (" EnableFlags = 0x%08lX\n", (ULONG) ReadField (EnableFlags));
  1591. dprintf (" MaximumFileSize = %ld\n", (ULONG) ReadField (MaximumFileSize));
  1592. dprintf (" LogFileMode = 0x%08lX\n", (ULONG) ReadField (LogFileMode));
  1593. dprintf (" LoggerMode = 0x%08lX\n", (ULONG) ReadField (LoggerMode));
  1594. dprintf (" FlushTimer = %I64u\n", ReadField (FlushTimer));
  1595. dprintf (" FirstBufferOffset = %I64u\n", ReadField (FirstBufferOffset));
  1596. dprintf (" ByteOffset = %I64u\n", ReadField (ByteOffset));
  1597. dprintf (" BufferAgeLimit = %I64d\n", ReadField (BufferAgeLimit));
  1598. dprintf (" LoggerName = '");
  1599. printUnicodeFromStruct (tarAddress, "NT!_WMI_LOGGER_CONTEXT", "LoggerName");
  1600. dprintf ( "'\n");
  1601. dprintf (" LogFileName = '");
  1602. printUnicodeFromStruct (tarAddress, "NT!_WMI_LOGGER_CONTEXT", "LogFileName");
  1603. dprintf ( "'\n");
  1604. }
  1605. }
  1606. return;
  1607. }
  1608. //+---------------------------------------------------------------------------
  1609. //
  1610. // Function: DECLARE_API(searchpath)
  1611. //
  1612. // Synopsis: LOG DUMP: Sets the trace format search path
  1613. //
  1614. // Arguments: <Path>
  1615. //
  1616. // Returns: <VOID>
  1617. //
  1618. // History: 7-03-2000 t-dbloom Created
  1619. //
  1620. // Notes:
  1621. //
  1622. //----------------------------------------------------------------------------
  1623. DECLARE_API( searchpath )
  1624. {
  1625. const CHAR *argPtr;
  1626. size_t sztLen;
  1627. LPTSTR lppath;
  1628. LPWSTR lppathW;
  1629. int len, waslen = 0;
  1630. // Defaults
  1631. lppath = NULL;
  1632. lppathW = NULL;
  1633. // Path ?
  1634. if (args) {
  1635. argPtr = args + strspn (args, " \t\n");
  1636. if (strlen (argPtr)) {
  1637. sztLen = strcspn (argPtr, " \t\n,");
  1638. lppath = (LPTSTR)malloc((sztLen + 1) * sizeof(TCHAR));
  1639. if(lppath != NULL) {
  1640. memcpy (lppath, argPtr, sztLen);
  1641. lppath[sztLen] = '\000';
  1642. }
  1643. }
  1644. }
  1645. if(lppath != NULL) {
  1646. //Convert to Unicode
  1647. while (((len = MultiByteToWideChar(CP_ACP, 0, lppath, sztLen, lppathW, waslen)) - waslen) > 0) {
  1648. if (len - waslen > 0 ) {
  1649. if (lppathW != NULL) {
  1650. free(lppathW);
  1651. }
  1652. lppathW = (LPWSTR)malloc((len + 1) * sizeof(wchar_t)) ;
  1653. if ( !lppathW ) {
  1654. dprintf("Memory allocation failed.\n");
  1655. return;
  1656. }
  1657. waslen = len;
  1658. }
  1659. }
  1660. if(lppathW != NULL) {
  1661. lppathW[len] = L'\000';
  1662. }
  1663. if(g_fpSetTraceFormatParameter == NULL) {
  1664. g_fpSetTraceFormatParameter = GetAddr("SetTraceFormatParameter");
  1665. }
  1666. if(g_fpSetTraceFormatParameter != NULL) {
  1667. g_fpSetTraceFormatParameter(ParameterTraceFormatSearchPath, lppathW);
  1668. }
  1669. free(lppath);
  1670. if(lppathW != NULL){
  1671. free(lppathW);
  1672. }
  1673. }
  1674. lppathW = NULL;
  1675. if(g_fpGetTraceFormatSearchPath == NULL) {
  1676. g_fpGetTraceFormatSearchPath = GetAddr("GetTraceFormatSearchPath");
  1677. }
  1678. if(g_fpGetTraceFormatSearchPath != NULL) {
  1679. lppathW = (LPWSTR)g_fpGetTraceFormatSearchPath();
  1680. }
  1681. // Show new search path
  1682. dprintf ("WMI Set Trace Format Search Path: Debugger Extension. Path = '%S'\n", lppathW);
  1683. return;
  1684. }
  1685. //+---------------------------------------------------------------------------
  1686. //
  1687. // Function: DECLARE_API(guidfile)
  1688. //
  1689. // Synopsis: LOG DUMP: Sets guid file name (if not set, the default is "default.tmf")
  1690. //
  1691. // Arguments: <Path>
  1692. //
  1693. // Returns: <VOID>
  1694. //
  1695. // History: 7-10-2000 t-dbloom Created
  1696. //
  1697. // Notes:
  1698. //
  1699. //----------------------------------------------------------------------------
  1700. DECLARE_API( guidfile )
  1701. {
  1702. const CHAR *argPtr;
  1703. size_t sztLen;
  1704. if (args) {
  1705. argPtr = args + strspn (args, " \t\n");
  1706. if (strlen (argPtr)) {
  1707. //only change name if it is different from what is already stored
  1708. if(_stricmp(argPtr, g_pszGuidFileName)){
  1709. sztLen = strcspn (argPtr, " \t\n,");
  1710. //make sure string length will not overrun buffer
  1711. if(sztLen >= MAX_PATH) {
  1712. sztLen = MAX_PATH - 1;
  1713. }
  1714. memcpy (g_pszGuidFileName, argPtr, sztLen);
  1715. g_pszGuidFileName[sztLen] = '\000';
  1716. if(g_GuidListHeadPtr != NULL) {
  1717. if(g_fpCleanupTraceEventList == NULL) {
  1718. g_fpCleanupTraceEventList = GetAddr("CleanupTraceEventList");
  1719. }
  1720. if(g_fpCleanupTraceEventList != NULL) {
  1721. g_fpCleanupTraceEventList (g_GuidListHeadPtr);
  1722. } else {
  1723. dprintf ("ERROR: Failed to clean up Guid list.\n");
  1724. }
  1725. g_GuidListHeadPtr = NULL;
  1726. }
  1727. }
  1728. }
  1729. }
  1730. dprintf("WMI Set Trace Guid File Name: Debugger Extension. File = '%s'\n", g_pszGuidFileName);
  1731. }
  1732. //+---------------------------------------------------------------------------
  1733. //
  1734. // Function: DECLARE_API(dynamicprint)
  1735. //
  1736. // Synopsis: LOG DUMP: Determines if dynamic tracing messaged are processed and printed, or just thrown away
  1737. //
  1738. // Arguments: <Path>
  1739. //
  1740. // Returns: <VOID>
  1741. //
  1742. // History: 7-10-2000 t-dbloom Created
  1743. //
  1744. // Notes:
  1745. //
  1746. //----------------------------------------------------------------------------
  1747. DECLARE_API( dynamicprint )
  1748. {
  1749. const CHAR *argPtr;
  1750. LPSTR lpValue = NULL;
  1751. if (args) {
  1752. argPtr = args + strspn (args, " \t\n");
  1753. } else {
  1754. dprintf("Invalid parameters\n");
  1755. return;
  1756. }
  1757. if(!_stricmp(argPtr, "1") ){
  1758. lpValue = "ON";
  1759. g_ulPrintDynamicMessages = 1;
  1760. } else if(!_stricmp(argPtr, "0")) {
  1761. lpValue = "OFF";
  1762. g_ulPrintDynamicMessages = 0;
  1763. } else {
  1764. dprintf("'%s' is not a valid value. The valid values are 1 and 0 (on and off, respectively)\n", argPtr);
  1765. }
  1766. if(lpValue != NULL) {
  1767. dprintf("WMI Set Trace Dynamic Print: Debugger Extension. Printing is now '%s'\n", lpValue);
  1768. }
  1769. }
  1770. DECLARE_API( kdtracing )
  1771. {
  1772. ULONG ulStatus = 0;
  1773. ULONG ulLoggerId;
  1774. LPSTR lpValue = NULL;
  1775. ULONG ulTracingOn = 0;
  1776. TARGET_ADDRESS LoggerContext;
  1777. ULONG LoggerMode;
  1778. ULONG Offset;
  1779. ULONG ulBytesWritten;
  1780. TARGET_ADDRESS PhysAddr;
  1781. PVOID BufferCallback;
  1782. PVOID fpKdReportTraceData;
  1783. const CHAR *argPtr;
  1784. size_t sztLen;
  1785. // Defaults
  1786. ulLoggerId = 1;
  1787. // LoggerId ?
  1788. if (args && args[0]) {
  1789. ulLoggerId = (ULONG) GetExpression (args);
  1790. }
  1791. argPtr = args + strspn (args, " \t\n");
  1792. sztLen = strspn (argPtr, "0123456789");
  1793. if (sztLen > 0) {
  1794. argPtr += sztLen;
  1795. }
  1796. // Guid Definition File
  1797. argPtr = argPtr + strspn (argPtr, " \t\n,");
  1798. if(!_stricmp(argPtr, "1") ) {
  1799. lpValue = "ON";
  1800. ulTracingOn = 1;
  1801. } else if(!_stricmp(argPtr, "0")) {
  1802. lpValue = "OFF";
  1803. ulTracingOn = 0;
  1804. } else {
  1805. dprintf("'%s' is not a valid value. The valid values are 1 and 0 (on and off, respectively)\n", argPtr);
  1806. }
  1807. if(lpValue != NULL) {
  1808. LoggerContext = FindLoggerContext(ulLoggerId);
  1809. if(LoggerContext != 0) {
  1810. // Setup ReadField's Context, Find Buffer Size
  1811. InitTypeRead (LoggerContext, NT!_WMI_LOGGER_CONTEXT);
  1812. LoggerMode = (ULONG)ReadField(LoggerMode);
  1813. BufferCallback = (PVOID)ReadField(BufferCallback);
  1814. if(GetTypeSize("KdReportTraceData") != 0){
  1815. fpKdReportTraceData = (PVOID)GetExpression("KdReportTraceData");
  1816. } else {
  1817. dprintf("ERROR: Could not find proper callback function in symbol file\n");
  1818. return;
  1819. }
  1820. if(ulTracingOn) {
  1821. LoggerMode |= EVENT_TRACE_KD_FILTER_MODE;
  1822. BufferCallback = fpKdReportTraceData;
  1823. } else {
  1824. LoggerMode &= ~EVENT_TRACE_KD_FILTER_MODE;
  1825. if(BufferCallback == fpKdReportTraceData) {
  1826. BufferCallback = NULL;
  1827. }
  1828. }
  1829. //Get the address of the LoggerMode by finding the offset into the structure
  1830. //so it can be written to
  1831. if(GetFieldOffset("NT!_WMI_LOGGER_CONTEXT", "LoggerMode", &Offset) == 0) {
  1832. //Add offset to base address and convert to physical
  1833. if(TranslateVirtualToPhysical(LoggerContext + (TARGET_ADDRESS)Offset, &PhysAddr)){
  1834. WritePhysical(PhysAddr, &LoggerMode, sizeof(ULONG), &ulBytesWritten);
  1835. }
  1836. } else {
  1837. dprintf("ERROR: Could not change tracing mode for logger %d\n", ulLoggerId);
  1838. return;
  1839. }
  1840. //Do the same for the BufferCallback as above
  1841. if(GetFieldOffset("NT!_WMI_LOGGER_CONTEXT", "BufferCallback", &Offset) == 0) {
  1842. if(TranslateVirtualToPhysical(LoggerContext + (TARGET_ADDRESS)Offset, &PhysAddr)){
  1843. WritePhysical(PhysAddr, &BufferCallback, sizeof(PVOID), &ulBytesWritten);
  1844. }
  1845. } else {
  1846. dprintf("ERROR: Could not change tracing mode for logger &d\n", ulLoggerId);
  1847. return;
  1848. }
  1849. dprintf("WMI KD Tracing: Debugger Extension. KD tracing is now '%s' for logger %d\n", lpValue, ulLoggerId);
  1850. }
  1851. }
  1852. }
  1853. VOID
  1854. wmiDynamicDumpProc(
  1855. PDEBUG_CONTROL Ctrl,
  1856. ULONG Mask,
  1857. PLIST_ENTRY g_GuidListHeadPtr,
  1858. PVOID pBuffer,
  1859. ULONG ulBufferLen
  1860. )
  1861. //+---------------------------------------------------------------------------
  1862. //
  1863. // Function: wmiDynamicDumpProc
  1864. //
  1865. // Synopsis: Called by WmiFormatTraceData to process the buffers as the come in through a live
  1866. // debugging session
  1867. //
  1868. // Arguments: Ctrl -> used for the Output function
  1869. // Mask -> passed directly to the Output function
  1870. // g_GuidListHeadPtr
  1871. // pBuffer -> buffer to be processed
  1872. // ulBufferLen -> size of buffer
  1873. //
  1874. // Returns: <VOID>
  1875. //
  1876. // History: 7-10-2000 t-dbloom Created
  1877. //
  1878. // Notes:
  1879. //
  1880. //----------------------------------------------------------------------------
  1881. {
  1882. WMIBUFFERINFO stBufferInfo;
  1883. ULONG size;
  1884. ULONG offset;
  1885. WMI_HEADER_TYPE headerType;
  1886. ULONG Alignment;
  1887. WCHAR wcaOutputLine[4096];
  1888. //Need to determine alignment based on architecture of target machine
  1889. //I believe alignment is always 8 ??
  1890. Alignment = 8;
  1891. memset (&stBufferInfo, 0, sizeof (stBufferInfo));
  1892. stBufferInfo.BufferSource = WMIBS_TRANSITION_LIST;
  1893. stBufferInfo.Buffer = pBuffer;
  1894. stBufferInfo.BufferSize = ulBufferLen;
  1895. stBufferInfo.Alignment = Alignment;
  1896. stBufferInfo.ProcessorNumber = ~((ULONG)0);
  1897. offset = WmiGetFirstTraceOffset (&stBufferInfo);
  1898. // Inspect Each Event
  1899. while ((headerType = WmiGetTraceHeader (pBuffer, offset, &size)) != WMIHT_NONE) {
  1900. ULONG ulInfo;
  1901. union {
  1902. EVENT_TRACE stEvent;
  1903. CHAR caEvent[4096];
  1904. } u;
  1905. if (CheckControlC()) break;
  1906. // Get a consistant header
  1907. ulInfo = WmiParseTraceEvent (pBuffer, offset, headerType, &u, sizeof (u));
  1908. wcaOutputLine[0] = 0;
  1909. if(g_fpFormatTraceEvent == NULL) {
  1910. g_fpFormatTraceEvent = GetAddr(FormatTraceEventString);
  1911. }
  1912. if(g_fpFormatTraceEvent != NULL) {
  1913. g_fpFormatTraceEvent (g_GuidListHeadPtr, (PEVENT_TRACE) &u.stEvent,
  1914. (TCHAR *) wcaOutputLine, sizeof (wcaOutputLine),
  1915. (TCHAR *) NULL);
  1916. } else {
  1917. return;
  1918. }
  1919. Ctrl->lpVtbl->Output(Ctrl, Mask, "%s\n", wcaOutputLine);
  1920. size = ((size + (Alignment-1)) / Alignment) * Alignment; //BUGBUG: Need fix in GetTraceHeader or WmiFlush. Then remove this line.
  1921. offset += size; // Move to next entry.
  1922. if(offset > ulBufferLen) {
  1923. Ctrl->lpVtbl->Output(Ctrl, Mask, "Past buffer end.\n");
  1924. break;
  1925. }
  1926. }
  1927. }
  1928. ULONG
  1929. WmiFormatTraceData(
  1930. PDEBUG_CONTROL Ctrl,
  1931. ULONG Mask,
  1932. ULONG DataLen,
  1933. PVOID Data
  1934. )
  1935. //+---------------------------------------------------------------------------
  1936. //
  1937. // Function: WmiFormatTraceData
  1938. //
  1939. // Synopsis: Implementation of function called by debugger when kd tracing is enabled through
  1940. // tracelog.
  1941. //
  1942. // Arguments: Ctrl
  1943. // Mask
  1944. // DataLen -> size of buffer
  1945. // Data -> buffer to be processed
  1946. //
  1947. // Returns: 0 (has no meaning for now..)
  1948. //
  1949. // History: 7-10-2000 t-dbloom Created
  1950. //
  1951. // Notes:
  1952. //
  1953. //----------------------------------------------------------------------------
  1954. {
  1955. int i = 1;
  1956. ULONG_PTR ulStatus = 0;
  1957. if(g_ulPrintDynamicMessages) {
  1958. if(g_GuidListHeadPtr == NULL) {
  1959. if(g_fpGetTraceGuids == NULL) {
  1960. g_fpGetTraceGuids = GetAddr(GetTraceGuidsString);
  1961. }
  1962. if(g_fpGetTraceGuids != NULL) {
  1963. ulStatus = g_fpGetTraceGuids ((TCHAR *) g_pszGuidFileName, &g_GuidListHeadPtr);
  1964. }
  1965. if (ulStatus == 0) {
  1966. dprintf ("Failed to open Guid file '%hs'\n", g_pszGuidFileName);
  1967. return 0;
  1968. }
  1969. }
  1970. wmiDynamicDumpProc (Ctrl, Mask, g_GuidListHeadPtr, Data, DataLen);
  1971. }
  1972. return 0;
  1973. }
  1974. FARPROC GetAddr(
  1975. LPCSTR lpProcName
  1976. )
  1977. //+---------------------------------------------------------------------------
  1978. //
  1979. // Function: GetAddr
  1980. //
  1981. // Synopsis: Used to get the proc addr of a function in TracePrt. Prints error message when
  1982. // needed.
  1983. //
  1984. // Arguments: lpProcName -> name of procedure to be fetched
  1985. //
  1986. // Returns: <VOID>
  1987. //
  1988. // History: 7-10-2000 t-dbloom Created
  1989. //
  1990. // Notes:
  1991. //
  1992. //----------------------------------------------------------------------------
  1993. {
  1994. FARPROC addr = NULL;
  1995. //See if the handle to TracePrt has already been fetched
  1996. if(g_hmTracePrtHandle == NULL) {
  1997. g_hmTracePrtHandle = getTracePrtHandle();
  1998. }
  1999. //If TracePrt handle exists, GetProcAddress
  2000. if(g_hmTracePrtHandle != NULL) {
  2001. addr = GetProcAddress(g_hmTracePrtHandle, lpProcName);
  2002. }
  2003. //Error if addr is null
  2004. if(addr == NULL) {
  2005. dprintf("ERROR: Could not properly load traceprt.dll\n", lpProcName);
  2006. }
  2007. return addr;
  2008. }
  2009. HMODULE getTracePrtHandle(
  2010. )
  2011. //+---------------------------------------------------------------------------
  2012. //
  2013. // Function: getTracePrtHandle
  2014. //
  2015. // Synopsis: Used to get a handle to the TracePrt dll. First looks in the directory that wmitrace
  2016. // is in, and if it cannot find it there, it looks in the default location (no path given).
  2017. //
  2018. // Arguments: lpProcName -> name of procedure to be fetched
  2019. //
  2020. // Returns: Handle to TracePrt dll, if found
  2021. //
  2022. // History: 7-10-2000 t-dbloom Created
  2023. //
  2024. // Notes:
  2025. //
  2026. //----------------------------------------------------------------------------
  2027. {
  2028. HMODULE handle = NULL;
  2029. TCHAR drive[10];
  2030. TCHAR filename[MAX_PATH];
  2031. TCHAR path[MAX_PATH];
  2032. TCHAR file[MAX_PATH];
  2033. TCHAR ext[MAX_PATH];
  2034. if(g_hmWmiTraceHandle == NULL) {
  2035. g_hmWmiTraceHandle = GetModuleHandle("wmiTrace.dll");
  2036. }
  2037. if (GetModuleFileName(g_hmWmiTraceHandle, filename, MAX_PATH) == MAX_PATH) {
  2038. filename[MAX_PATH-1] = '\0' ;
  2039. }
  2040. _splitpath( filename, drive, path, file, ext );
  2041. strcpy(file, "traceprt");
  2042. _makepath( filename, drive, path, file, ext );
  2043. //Try to get a handle to traceprt using full path as obtained above using path of wmitrace
  2044. handle = LoadLibrary(filename);
  2045. //If this didn't work, just try traceprt.dll without a path
  2046. if(handle == NULL) {
  2047. handle = LoadLibrary("traceprt.dll");
  2048. }
  2049. return handle;
  2050. }
  2051. BOOL WINAPI DllMain(
  2052. HINSTANCE hinstDLL, // handle to DLL module
  2053. DWORD fdwReason, // reason for calling function
  2054. LPVOID lpReserved ) // reserved
  2055. {
  2056. // Perform actions based on the reason for calling.
  2057. switch( fdwReason )
  2058. {
  2059. case DLL_PROCESS_ATTACH:
  2060. EtwpInitializeDll();
  2061. break;
  2062. case DLL_THREAD_ATTACH:
  2063. break;
  2064. case DLL_THREAD_DETACH:
  2065. // Do thread-specific cleanup.
  2066. break;
  2067. case DLL_PROCESS_DETACH:
  2068. EtwpDeinitializeDll(); // Perform any necessary cleanup.
  2069. break;
  2070. }
  2071. return TRUE; // Successful DLL_PROCESS_ATTACH.
  2072. }