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.

3558 lines
106 KiB

  1. /*++
  2. Copyright (c) 1995-2000 Microsoft Corporation
  3. Module Name:
  4. kernrate.c
  5. Abstract:
  6. This program records the rate of various events over a selected
  7. period of time. It uses the kernel profiling mechanism and iterates
  8. through the available profile sources to produce an overall profile
  9. for the various kernel components.
  10. Usage:
  11. kernrate
  12. Author:
  13. John Vert (jvert) 31-Mar-1995
  14. Revision History:
  15. The original MS version has been extensively modified by Thierry Fevrier.
  16. 01/12/2000 Thierry
  17. Kernrate is under the SD tree. From now on, please refer to filelog outputs for
  18. details on modifications...
  19. 01/11/2000 Thierry
  20. Ported to test IA64 Hardware Performance Counters.
  21. 10/02/97 11:48a Thierry
  22. Fixed the format of RATE_SUMMARY TotalCount.
  23. Fixed outputs for large ULONG numbers.
  24. 10/01/97 5:28p Thierry
  25. Added image file and debug file checksum/timestamp check using imagehlp
  26. callbacks.
  27. Modified processor times display using I64u formats.
  28. Defined UInt64PerCent() function.
  29. MODULE structures are allocated using calloc().
  30. Changed MODULE structure to contain FileName and FullName fields.
  31. Added ToDoList block to remind us about the current problems for this
  32. program.
  33. 9/30/97 11:01a Thierry
  34. Added "-u" option to present undecorated symbols
  35. Usage(): Print version info
  36. 9/05/97 2:41p tkjos
  37. Changed raw output to include all symbols associated with each bucket
  38. 9/05/97 2:15p Thierry
  39. Added the '-j' option to specify a symbol path that will be prepended
  40. to the default IMAGEHLP sysmbol search path.
  41. 9/05/97 11:37a Thierry
  42. Fixed Usage() string for -v and -b options.
  43. 9/05/97 10:56a tkjos
  44. Added -v option for "verbose" output. This causes all data to be
  45. be evaluated by rounding the bucket counters both up and down to the
  46. nearest symbol. By default, only the rounded down data is shown. Also
  47. added a '-b BucketSize' option to allow the bucket size to be changed.
  48. 9/05/97 1:49a Thierry
  49. no real modification. only a remote check-in.
  50. 9/05/97 12:58a Thierry
  51. SetModuleName() definition.
  52. 9/05/97 12:48a Thierry
  53. Fixed limitation that module name passed as a zoomed module name or by
  54. looking at the process modules should be limited with 7 characters.
  55. 9/04/97 6:44p Thierry
  56. Added the possibility to use no source short name with the '-i' option.
  57. In this case, the default platform independant "Time" source is used.
  58. 9/04/97 6:27p Thierry
  59. Added the options -lx and -r to the usage string.
  60. 9/04/97 6:02p Thierry
  61. Added the update of source short name for the static and dynamic
  62. sources. This allows users to use these short names to disable sources.
  63. 9/04/97 3:06p Thierry
  64. Added '-lx' option to list supported sources and exit immediately
  65. GetConfiguration(): option '-i Source 0' disables the source.
  66. 9/04/97 10:40a tkjos
  67. Fixed defect in accumulation of counters for zoomed modules. The index
  68. for the end of each function was being calculated incorrectly causing
  69. counter information to be lost or to be assigned to the wrong functions.
  70. 9/03/97 12:40p tkjos
  71. Added raw addresses to -r option.
  72. 8/28/97 7:43a Thierry
  73. Added '-l' option to list available source types and their default
  74. interval rate.
  75. Added '-i' option to allow users the changing of default interval
  76. rates.
  77. --*/
  78. // KERNRATE Implementation Notes:
  79. //
  80. // 01/10/2000 - Thierry
  81. // The following code assumes that a kernrate compiled for a specific
  82. // platform, executes and processes perf data only for that platform.
  83. //
  84. // KERNRATE ToDoList:
  85. //
  86. // Thierry 09/30/97:
  87. // - KernRate does not clean the ImageHlp API in case of exceptions. I have
  88. // just added a SymCleanup() call at the normal exit of this program but
  89. // it is not sufficient. We should revisit this one day...
  90. //
  91. // Thierry 07/01/2000:
  92. // - Kernrate and the Kernel Profiling objects code assume that code sections
  93. // that we are profiling are not larger than 4GB.
  94. //
  95. //
  96. // If under our build environment'S', we want to get all our
  97. // favorite debug macros defined.
  98. //
  99. #if DBG // NTBE environment
  100. #if NDEBUG
  101. #undef NDEBUG // <assert.h>: assert() is defined
  102. #endif // NDEBUG
  103. #define _DEBUG // <crtdbg.h>: _ASSERT(), _ASSERTE() are defined.
  104. #define DEBUG 1 // our internal file debug flag
  105. #elif _DEBUG // VC++ environment
  106. #ifndef NEBUG
  107. #define NDEBUG
  108. #endif // !NDEBUG
  109. #define DEBUG 1 // our internal file debug flag
  110. #endif
  111. //
  112. // Include System Header files
  113. //
  114. #include <nt.h>
  115. #include <ntrtl.h>
  116. #include <nturtl.h>
  117. #include <windows.h>
  118. #include <imagehlp.h>
  119. #include <assert.h>
  120. #include <stdio.h>
  121. #include <stdlib.h>
  122. #include <search.h>
  123. #include <string.h>
  124. #include <memory.h>
  125. #include <ctype.h>
  126. #include <..\pperf\pstat.h>
  127. #include ".\kernrate.rc"
  128. #define FPRINTF (void)fprintf
  129. #define MAX_SYMNAME_SIZE 1024
  130. CHAR symBuffer[sizeof(IMAGEHLP_SYMBOL64)+MAX_SYMNAME_SIZE];
  131. PIMAGEHLP_SYMBOL64 Symbol = (PIMAGEHLP_SYMBOL64)symBuffer;
  132. typedef enum _VERBOSE_ENUM {
  133. VERBOSE_NONE = 0, //
  134. VERBOSE_IMAGEHLP = 0x1, //
  135. VERBOSE_PROFILING = 0x2, //
  136. VERBOSE_INTERNALS = 0x4, //
  137. VERBOSE_MODULES = 0x8, //
  138. VERBOSE_DEFAULT = VERBOSE_IMAGEHLP
  139. } VERBOSE_ENUM;
  140. typedef struct _VERBOSE_DEFINITION {
  141. VERBOSE_ENUM VerboseEnum;
  142. const char * const VerboseString;
  143. } VERBOSE_DEFINITION, *PVERBOSE_DEFINITION;
  144. VERBOSE_DEFINITION VerboseDefinition[] = {
  145. { VERBOSE_NONE, "None" },
  146. { VERBOSE_IMAGEHLP, "Displays ImageHlp operations" },
  147. { VERBOSE_PROFILING, "Displays Profiling operations" },
  148. { VERBOSE_INTERNALS, "Displays Internals operations" },
  149. { VERBOSE_MODULES, "Displays Modules operations" },
  150. { VERBOSE_NONE, NULL }
  151. };
  152. ULONG Verbose = VERBOSE_NONE;
  153. BOOL RoundingVerboseOutput = FALSE;
  154. ULONG ZoomBucket = 16;
  155. ULONG Log2ZoomBucket = 4;
  156. #define ZOOM_BUCKET ZoomBucket
  157. #define LOG2_ZOOM_BUCKET Log2ZoomBucket
  158. typedef enum _KERNRATE_NAMESPACE {
  159. cMAPANDLOAD_READONLY = TRUE,
  160. cDONOT_ALLOCATE_DESTINATION_STRING = FALSE,
  161. } eKERNRATE_NAMESPACE;
  162. //
  163. // Type definitions
  164. //
  165. typedef struct _SOURCE {
  166. PCHAR Name; // pstat EVENTID.Description
  167. KPROFILE_SOURCE ProfileSource;
  168. PCHAR ShortName; // pstat EVENTID.ShortName
  169. ULONG DesiredInterval;
  170. ULONG Interval;
  171. } SOURCE, *PSOURCE;
  172. typedef struct _RATE_DATA {
  173. ULONGLONG StartTime;
  174. ULONGLONG TotalTime;
  175. ULONGLONG TotalCount;
  176. ULONGLONG Rate; // Events/Second
  177. HANDLE ProfileHandle;
  178. ULONG CurrentCount;
  179. PULONG ProfileBuffer;
  180. } RATE_DATA, *PRATE_DATA;
  181. typedef enum _MODULE_NAMESPACE {
  182. cMODULE_NAME_STRLEN = 40, // maximum module name, including '\0'
  183. } eMODULE_NAMESPACE;
  184. typedef struct _MODULE {
  185. struct _MODULE *Next;
  186. HANDLE Process;
  187. ULONG64 Base;
  188. ULONG Length;
  189. BOOLEAN Zoom;
  190. CHAR module_Name[cMODULE_NAME_STRLEN]; // filename w/o its extension
  191. PCHAR module_FileName; // filename with its extension
  192. PCHAR module_FullName; // full pathname
  193. RATE_DATA Rate[];
  194. } MODULE, *PMODULE;
  195. #define ModuleFileName( _Module ) \
  196. ( (_Module)->module_FileName ? (_Module)->module_FileName : (_Module)->module_Name )
  197. #define ModuleFullName( _Module ) \
  198. ( (_Module)->module_FullName ? (_Module)->module_FullName : ModuleFileName( _Module ) )
  199. typedef struct _RATE_SUMMARY {
  200. ULONGLONG TotalCount;
  201. PMODULE *Modules;
  202. ULONG ModuleCount;
  203. } RATE_SUMMARY, *PRATE_SUMMARY;
  204. #define IsValidHandle( _Hdl ) ( ( (_Hdl) != (HANDLE)0 ) && ( (_Hdl) != INVALID_HANDLE_VALUE ) )
  205. //
  206. // Thierry - FIXFIX - These processor level enums should be defined in public headers.
  207. // ntexapi.h - NtQuerySystemInformation( SystemProcessorInformation).
  208. //
  209. // Define them locally.
  210. //
  211. typedef enum _PROCESSOR_LEVEL {
  212. IA64_MERCED = 0x1,
  213. IA64_ITANIUM = IA64_MERCED,
  214. IA64_MCKINLEY = 0x2
  215. } PROCESSOR_LEVEL;
  216. //
  217. // Global variables
  218. //
  219. HANDLE DoneEvent;
  220. DWORD ChangeInterval = 1000;
  221. DWORD SleepInterval = 0;
  222. ULONG ModuleCount=0;
  223. ULONG ZoomCount;
  224. PMODULE ZoomList = NULL;
  225. PMODULE CallbackCurrent;
  226. BOOLEAN RawData = FALSE;
  227. BOOLEAN RawDisasm = FALSE;
  228. HANDLE SymHandle = (HANDLE)-1;
  229. static CHAR gUserSymbolPath[256];
  230. static CHAR gSymbolPath[2*256];
  231. static DWORD gSymOptions;
  232. static PMODULE gCurrentModule = (PMODULE)0;
  233. //
  234. // The desired intervals are computed to give approximately
  235. // one interrupt per millisecond and be a nice even power of 2
  236. //
  237. enum _STATIC_SOURCE_TYPE {
  238. SOURCE_TIME = 0,
  239. };
  240. #define SOURCE_ALIGN_FIXUP_DEFAULT_DESIRED_INTERVAL 0
  241. #if defined(_ORIGINAL_CODE) && defined(_M_X86)
  242. //
  243. // The MS original code specifed that Alignment Fixup as a default source
  244. // for X86, even if the Kernel/Hal do not support it for these platforms.
  245. //
  246. #undef SOURCE_ALIGN_FIXUP_DEFAULT_DESIRED_INTERVAL
  247. #define SOURCE_ALIGN_FIXUP_DEFAULT_DESIRED_INTERVAL 1
  248. #endif
  249. SOURCE StaticSources[] = {
  250. {"Time", ProfileTime, "time" , 1000, 1000},
  251. {"Alignment Fixup", ProfileAlignmentFixup, "alignfixup" , SOURCE_ALIGN_FIXUP_DEFAULT_DESIRED_INTERVAL,0},
  252. {"Total Issues", ProfileTotalIssues, "totalissues", 131072,0},
  253. {"Pipeline Dry", ProfilePipelineDry, "pipelinedry", 131072,0},
  254. {"Load Instructions", ProfileLoadInstructions, "loadinst" , 65536,0},
  255. {"Pipeline Frozen", ProfilePipelineFrozen, "pilelinefrz", 131072,0},
  256. {"Branch Instructions", ProfileBranchInstructions, "branchinst" , 65536,0},
  257. {"Total Nonissues", ProfileTotalNonissues, "totalnoniss", 131072,0},
  258. {"Dcache Misses", ProfileDcacheMisses, "dcachemiss" , 16384,0},
  259. {"Icache Misses", ProfileIcacheMisses, "icachemiss" , 16384,0},
  260. {"Cache Misses", ProfileCacheMisses, "cachemiss" , 16384,0},
  261. {"Branch Mispredictions", ProfileBranchMispredictions, "branchpred" , 16384,0},
  262. {"Store Instructions", ProfileStoreInstructions, "storeinst" , 65536,0},
  263. {"Floating Point Instr", ProfileFpInstructions, "fpinst" , 65536,0},
  264. {"Integer Instructions", ProfileIntegerInstructions, "intinst" , 65536,0},
  265. {"Dual Issues", Profile2Issue, "2issue" , 65536,0},
  266. {"Triple Issues", Profile3Issue, "3issue" , 16384,0},
  267. {"Quad Issues", Profile4Issue, "4issue" , 16384,0},
  268. {"Special Instructions", ProfileSpecialInstructions, "specinst" , 16384,0},
  269. {"Cycles", ProfileTotalCycles, "totalcycles", 655360,0},
  270. {"Icache Issues", ProfileIcacheIssues, "icacheissue", 65536,0},
  271. {"Dcache Accesses", ProfileDcacheAccesses, "dcacheacces", 65536,0},
  272. {"MB Stall Cycles", ProfileMemoryBarrierCycles, "membarcycle", 32767,0},
  273. {"Load Linked Instructions", ProfileLoadLinkedIssues, "loadlinkiss", 16384,0},
  274. {NULL, ProfileMaximum, "", 0, 0}
  275. };
  276. #if defined(_IA64_)
  277. #include "merced.c"
  278. #endif // _IA64_
  279. PSOURCE Source = NULL;
  280. ULONG SourceMaximum = 0;
  281. //
  282. // Print format for event strings
  283. //
  284. ULONG TokenMaxLen = 12; // strlen("dcacheacces")
  285. ULONG DescriptionMaxLen = 25; // strlen("Load Linked Instructions")
  286. //
  287. // Function prototypes local to this module
  288. //
  289. PMODULE
  290. GetKernelModuleInformation(
  291. VOID
  292. );
  293. PMODULE
  294. GetProcessModuleInformation(
  295. IN HANDLE ProcessHandle
  296. );
  297. VOID
  298. CreateProfiles(
  299. IN PMODULE Root
  300. );
  301. PMODULE
  302. CreateNewModule(
  303. IN HANDLE ProcessHandle,
  304. IN PCHAR ModuleName,
  305. IN PCHAR ModuleFullName,
  306. IN ULONG64 ImageBase,
  307. IN ULONG ImageSize
  308. );
  309. VOID
  310. GetConfiguration(
  311. int argc,
  312. char *argv[]
  313. );
  314. ULONG
  315. InitializeProfileSourceInfo (
  316. VOID
  317. );
  318. ULONG
  319. NextSource(
  320. IN ULONG CurrentSource,
  321. IN PMODULE ModuleList
  322. );
  323. VOID
  324. StopSource(
  325. IN ULONG ProfileSourceIndex,
  326. IN PMODULE ModuleList
  327. );
  328. VOID
  329. StartSource(
  330. IN ULONG ProfileSource,
  331. IN PMODULE ModuleList
  332. );
  333. VOID
  334. OutputResults(
  335. IN FILE *Out,
  336. IN PMODULE ModuleList
  337. );
  338. VOID
  339. OutputModuleList(
  340. IN FILE *Out,
  341. IN PMODULE ModuleList,
  342. IN ULONG NumberModules
  343. );
  344. BOOL
  345. TkEnumerateSymbols(
  346. IN HANDLE SymHandle,
  347. IN PMODULE Current,
  348. IN PSYM_ENUMSYMBOLS_CALLBACK64 EnumSymbolsCallback
  349. );
  350. VOID
  351. CreateZoomedModuleList(
  352. IN PMODULE ZoomModule,
  353. IN ULONG RoundDown
  354. );
  355. BOOL
  356. CreateZoomModuleCallback(
  357. IN LPSTR szSymName,
  358. IN ULONG64 Address,
  359. IN ULONG Size,
  360. IN PVOID Cxt
  361. );
  362. VOID
  363. OutputLine(
  364. IN FILE *Out,
  365. IN ULONG ProfileSourceIndex,
  366. IN PMODULE Module,
  367. IN PRATE_SUMMARY RateSummary
  368. );
  369. VOID
  370. CreateDoneEvent(
  371. VOID
  372. );
  373. VOID
  374. OutputInterestingData(
  375. IN FILE *Out,
  376. IN RATE_DATA Data[],
  377. IN PCHAR Header
  378. );
  379. static
  380. VOID
  381. vVerbosePrint(
  382. ULONG Level,
  383. PCCHAR Msg,
  384. ...
  385. )
  386. {
  387. if ( Verbose & Level ) {
  388. UCHAR verbosePrintBuffer[512];
  389. va_list ap;
  390. va_start( ap, Msg );
  391. _vsnprintf( verbosePrintBuffer, sizeof( verbosePrintBuffer ), Msg, ap );
  392. va_end(ap);
  393. (void)fprintf( stderr, verbosePrintBuffer );
  394. }
  395. return;
  396. } // vVerbosePrint()
  397. #define VerbosePrint( _x_ ) vVerbosePrint _x_
  398. BOOL
  399. CtrlcH(
  400. DWORD dwCtrlType
  401. )
  402. {
  403. LARGE_INTEGER DueTime;
  404. if ( dwCtrlType == CTRL_C_EVENT ) {
  405. if (SleepInterval == 0) {
  406. SetEvent(DoneEvent);
  407. } else {
  408. DueTime.QuadPart = (ULONGLONG)-1;
  409. NtSetTimer(DoneEvent,
  410. &DueTime,
  411. NULL,
  412. NULL,
  413. FALSE,
  414. 0,
  415. NULL);
  416. }
  417. return TRUE;
  418. }
  419. return FALSE;
  420. } // CtrlcH()
  421. static VOID
  422. UsageVerbose(
  423. VOID
  424. )
  425. {
  426. PVERBOSE_DEFINITION pdef = VerboseDefinition;
  427. FPRINTF( stderr, " -v [VerboseLevels] Verbose output where VerboseLevels:\n");
  428. while( pdef->VerboseString ) {
  429. FPRINTF( stderr, " - %x %s\n", pdef->VerboseEnum,
  430. pdef->VerboseString
  431. );
  432. pdef++;
  433. }
  434. FPRINTF( stderr, " - Default value: %x\n", VERBOSE_DEFAULT);
  435. FPRINTF( stderr, " These verbose levels can be OR'ed.\n");
  436. return;
  437. } // UsageVerbose()
  438. static VOID
  439. Usage(
  440. VOID
  441. )
  442. {
  443. FPRINTF( stderr, "KERNRATE - Version: %s\n", VER_PRODUCTVERSION_STR );
  444. FPRINTF( stderr,
  445. "KERNRATE [-l] [-lx] [-r] [-z ModuleName] [-j SymbolPath] [-c RateInMsec] [-s Seconds] [-p ProcessId] [-i [SrcShortName] Rate]\n"
  446. " -b BucketSize Specify profiling bucket size (default = 16 bytes)\n"
  447. " -c RateInMsec Change source after N milliseconds (default 1000)\n"
  448. " -d Generate output rounding buckets up and down\n"
  449. " -i [SrcShortName] Rate Specify interrupt interval rate for the source specified by its ShortName\n"
  450. " -j SymbolPath Prepend SymbolPath the default imagehlp search path\n"
  451. " -l List the default interval rates for the supported sources\n"
  452. " -lx List the default interval rates for the supported sources and exits\n"
  453. " -p ProcessId Monitor process instead of kernel\n"
  454. " -r Raw data from zoomed modules\n"
  455. " -rd Raw data from zoomed modules with disassembly\n"
  456. " -s Seconds Stop collecting data after N seconds\n"
  457. " -u Present symbols in undecorated form\n"
  458. );
  459. UsageVerbose(); // -v switches
  460. FPRINTF( stderr,
  461. " -z ModuleName Zoom in on specified module\n"
  462. "\nWith the '-i' option, specifying a Rate value = 0 disables the source.\n"
  463. );
  464. #if defined(_M_IX86) || defined(_M_IA64)
  465. FPRINTF(stderr, "The default interrupt profiling source is Time @ %ld\n", Source[SOURCE_TIME].DesiredInterval);
  466. #endif /* !_M_IX86 */
  467. exit(1);
  468. } // Usage()
  469. VOID
  470. CreateDoneEvent(
  471. VOID
  472. )
  473. {
  474. LARGE_INTEGER DueTime;
  475. NTSTATUS Status;
  476. DWORD Error;
  477. if (SleepInterval == 0) {
  478. //
  479. // Create event that will indicate the test is complete.
  480. //
  481. DoneEvent = CreateEvent(NULL,
  482. TRUE,
  483. FALSE,
  484. NULL);
  485. if (DoneEvent == NULL) {
  486. Error = GetLastError();
  487. FPRINTF(stderr, "CreateEvent failed %d\n",Error);
  488. exit(Error);
  489. }
  490. } else {
  491. //
  492. // Create timer that will indicate the test is complete
  493. //
  494. Status = NtCreateTimer(&DoneEvent,
  495. MAXIMUM_ALLOWED,
  496. NULL,
  497. NotificationTimer);
  498. if (!NT_SUCCESS(Status)) {
  499. FPRINTF(stderr, "NtCreateTimer failed %08lx\n",Status);
  500. exit(Status);
  501. }
  502. DueTime.QuadPart = (ULONGLONG)SleepInterval * -10000;
  503. Status = NtSetTimer(DoneEvent,
  504. &DueTime,
  505. NULL,
  506. NULL,
  507. FALSE,
  508. 0,
  509. NULL);
  510. if (!NT_SUCCESS(Status)) {
  511. FPRINTF(stderr, "NtSetTimer failed %08lx\n",Status);
  512. exit(Status);
  513. }
  514. }
  515. } // CreateDoneEvent()
  516. static void
  517. CheckImageAndDebugFiles( IN PMODULE Module, IN PIMAGEHLP_DEFERRED_SYMBOL_LOAD Idsl )
  518. {
  519. LOADED_IMAGE image;
  520. assert( Module );
  521. assert( Idsl );
  522. if ( Module->module_FullName == (PCHAR)0 ) {
  523. FPRINTF( stderr, "KERNRATE: Failed checking module %s with its debug file %s...\n",
  524. ModuleFileName( Module ),
  525. Idsl->FileName
  526. );
  527. return;
  528. }
  529. //
  530. // Map and Load the current image file
  531. //
  532. if ( !MapAndLoad( Module->module_FullName, (LPSTR)0, &image, FALSE, cMAPANDLOAD_READONLY ) ) {
  533. BOOL notMapped = TRUE;
  534. //
  535. // Is the fullname string a module alias?.
  536. //
  537. if ( strchr( Module->module_FullName, ':' ) == (char)0 ) {
  538. char path[_MAX_PATH + ( 3 * sizeof(char) )];
  539. int c;
  540. for ( c = 'C' ; c <= 'Z' ; c++ ) {
  541. path[0] = (char)c;
  542. path[1] = ':';
  543. path[2] = '\0';
  544. strcat( path, Module->module_FullName );
  545. if ( MapAndLoad( path, (LPSTR)0, &image, FALSE, cMAPANDLOAD_READONLY ) ) {
  546. notMapped = FALSE;
  547. break;
  548. }
  549. }
  550. }
  551. if ( notMapped ) {
  552. FPRINTF(stderr, "KERNRATE: Failed mapping and checking module %s with its debug file %s...\n",
  553. ModuleFullName( Module ),
  554. Idsl->FileName
  555. );
  556. return;
  557. }
  558. }
  559. if ( Idsl->CheckSum ) {
  560. DWORD checkSum;
  561. DWORD idslCheckSum;
  562. DWORD timeStamp;
  563. idslCheckSum = Idsl->CheckSum;
  564. checkSum = image.FileHeader->OptionalHeader.CheckSum;
  565. if ( checkSum != idslCheckSum ) {
  566. FPRINTF( stderr, "*** WARNING: symbols checksum is wrong 0x%08x 0x%08x for %s\n",
  567. checkSum,
  568. idslCheckSum,
  569. Idsl->FileName
  570. );
  571. UnMapAndLoad( &image );
  572. return;
  573. }
  574. timeStamp = image.FileHeader->FileHeader.TimeDateStamp;
  575. if ( timeStamp != Idsl->TimeDateStamp ) {
  576. FPRINTF( stderr, "*** WARNING: symbols timestamp is wrong 0x%08x 0x%08x for %s\n",
  577. timeStamp,
  578. Idsl->TimeDateStamp,
  579. Idsl->FileName
  580. );
  581. }
  582. }
  583. UnMapAndLoad( &image );
  584. return;
  585. } // CheckImageAndDebugFiles()
  586. /* BEGIN_IMS SymbolCallbackFunction
  587. ******************************************************************************
  588. ****
  589. **** SymbolCallbackFunction ( )
  590. ****
  591. ******************************************************************************
  592. *
  593. * Function Description:
  594. *
  595. * The user function is called by IMAGEHLP at the specified operations.
  596. * Refer to the CBA_xxx values.
  597. *
  598. * Arguments:
  599. *
  600. * HANDLE hProcess :
  601. *
  602. * ULONG ActionCode :
  603. *
  604. * PVOID CallbackData :
  605. *
  606. * PVOID UserContext :
  607. *
  608. * Return Value:
  609. *
  610. * BOOL
  611. *
  612. * Algorithm:
  613. *
  614. * ToBeSpecified
  615. *
  616. * Globals Referenced:
  617. *
  618. * ToBeSpecified
  619. *
  620. * Exception Conditions:
  621. *
  622. * ToBeSpecified
  623. *
  624. * In/Out Conditions:
  625. *
  626. * ToBeSpecified
  627. *
  628. * Notes:
  629. *
  630. * ToBeSpecified
  631. *
  632. * ToDo List:
  633. *
  634. * ToBeSpecified
  635. *
  636. * Modification History:
  637. *
  638. * 9/30/97 TF Initial version
  639. *
  640. ******************************************************************************
  641. * END_IMS SymbolCallbackFunction */
  642. BOOL
  643. SymbolCallbackFunction(
  644. HANDLE hProcess,
  645. ULONG ActionCode,
  646. ULONG64 CallbackData,
  647. ULONG64 UserContext
  648. )
  649. {
  650. PIMAGEHLP_DEFERRED_SYMBOL_LOAD idsl;
  651. PIMAGEHLP_DUPLICATE_SYMBOL idup;
  652. PMODULE *pmodule;
  653. PMODULE module;
  654. IMAGEHLP_MODULE mi;
  655. // Note TF 09/97:
  656. // The default return value for this function is FALSE.
  657. //
  658. assert( UserContext );
  659. switch( ActionCode ) {
  660. case CBA_DEBUG_INFO:
  661. VerbosePrint(( VERBOSE_IMAGEHLP, "%s", (LPSTR)CallbackData ));
  662. return TRUE;
  663. case CBA_DEFERRED_SYMBOL_LOAD_START:
  664. idsl = (PIMAGEHLP_DEFERRED_SYMBOL_LOAD)CallbackData;
  665. pmodule = (PMODULE *)UserContext;
  666. module = *pmodule;
  667. _strlwr( idsl->FileName );
  668. VerbosePrint(( VERBOSE_IMAGEHLP, "Loading symbols for 0x%Ix %s...\n",
  669. idsl->BaseOfImage,
  670. idsl->FileName
  671. ));
  672. return ( ( module == (PMODULE)0 ) ? FALSE : TRUE );
  673. #if 0
  674. //
  675. // For KernRate, we should be looping through the ZoomList
  676. // and look after the same base. However, because of KernRate
  677. // CreateNewModule() ZoomList manipulation, this list is broken.
  678. // We should revisit this.
  679. // For now, I am using the UserContext.
  680. //
  681. module = ZoomList;
  682. while ( module ) {
  683. if ( idsl->BaseOfImage == (ULONG)module->Base ) {
  684. _strlwr( idsl->FileName );
  685. FPRINTF( stderr,
  686. "Loading symbols for 0x%08x %s...",
  687. idsl->BaseOfImage,
  688. idsl->FileName
  689. );
  690. return TRUE;
  691. }
  692. module = module->Next;
  693. }
  694. break;
  695. #endif // 0
  696. case CBA_DEFERRED_SYMBOL_LOAD_FAILURE:
  697. idsl = (PIMAGEHLP_DEFERRED_SYMBOL_LOAD) CallbackData;
  698. FPRINTF( stderr, "*** ERROR: Could not load symbols for 0x%Ix %s...\n",
  699. idsl->BaseOfImage,
  700. idsl->FileName
  701. );
  702. return FALSE;
  703. case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE:
  704. idsl = (PIMAGEHLP_DEFERRED_SYMBOL_LOAD) CallbackData;
  705. pmodule = (PMODULE *)UserContext;
  706. module = *pmodule;
  707. if ( module && module->Base == idsl->BaseOfImage ) {
  708. FPRINTF(stderr, "Loaded symbols for 0x%Ix %s -> %s\n",
  709. idsl->BaseOfImage,
  710. ModuleFullName( module ),
  711. idsl->FileName
  712. );
  713. CheckImageAndDebugFiles( module, idsl );
  714. if ( SymGetModuleInfo( SymHandle, idsl->BaseOfImage, &mi ) ) {
  715. if ( mi.SymType == SymNone ) {
  716. FPRINTF( stderr, "*** ERROR: Module load completed but symbols could not be loaded for %s\n",
  717. idsl->FileName
  718. );
  719. }
  720. }
  721. return TRUE;
  722. }
  723. #if 0
  724. pImage = pProcessCurrent->pImageHead;
  725. while (pImage) {
  726. if ((idsl->BaseOfImage == (ULONG)pImage->lpBaseOfImage) || ((ULONG)pImage->lpBaseOfImage == 0)) {
  727. pImage->szDebugPath[0] = 0;
  728. strncpy( pImage->szDebugPath, idsl->FileName, sizeof(pImage->szDebugPath) );
  729. _strlwr( pImage->szDebugPath );
  730. printf( "XXXX: %s\n", pImage->szDebugPath );
  731. if (idsl->CheckSum != pImage->dwCheckSum) {
  732. printf( "XXX: *** WARNING: symbols checksum is wrong 0x%08x 0x%08x for %s\n",
  733. pImage->dwCheckSum,
  734. idsl->CheckSum,
  735. pImage->szDebugPath
  736. );
  737. }
  738. if (SymGetModuleInfo( pProcessCurrent->hProcess, idsl->BaseOfImage, &mi )) {
  739. if (mi.SymType == SymNone) {
  740. printf( "XXX: *** ERROR: Module load completed but symbols could not be loaded for %s\n",
  741. pImage->szDebugPath
  742. );
  743. }
  744. }
  745. return TRUE;
  746. }
  747. pImage = pImage->pImageNext;
  748. }
  749. printf( "\n" );
  750. #endif // 0
  751. break;
  752. case CBA_SYMBOLS_UNLOADED:
  753. idsl = (PIMAGEHLP_DEFERRED_SYMBOL_LOAD) CallbackData;
  754. FPRINTF( stderr, "Symbols unloaded for 0x%Ix %s\n",
  755. idsl->BaseOfImage,
  756. idsl->FileName
  757. );
  758. return TRUE;
  759. case CBA_DUPLICATE_SYMBOL:
  760. idup = (PIMAGEHLP_DUPLICATE_SYMBOL) CallbackData;
  761. FPRINTF( stderr, "*** WARNING: Found %ld duplicate symbols for %s\n",
  762. idup->NumberOfDups,
  763. (idup->SelectedSymbol != (ULONG)-1) ? idup->Symbol[idup->SelectedSymbol].Name : "unknown symbol"
  764. );
  765. return TRUE;
  766. default:
  767. return FALSE;
  768. }
  769. return FALSE;
  770. } // SymbolCallBackFunction()
  771. static PUCHAR
  772. GetSymOptionsValues( DWORD SymOptions )
  773. {
  774. static UCHAR values[160];
  775. values[0] = '\0';
  776. if ( SymOptions & SYMOPT_CASE_INSENSITIVE ) {
  777. (void)strcat( values, "CASE_INSENSITIVE " );
  778. SymOptions &= ~SYMOPT_CASE_INSENSITIVE;
  779. }
  780. if ( SymOptions & SYMOPT_UNDNAME ) {
  781. (void)strcat( values, "UNDNAME " );
  782. SymOptions &= ~SYMOPT_UNDNAME;
  783. }
  784. if ( SymOptions & SYMOPT_DEFERRED_LOADS ) {
  785. (void)strcat( values, "DEFERRED_LOADS " );
  786. SymOptions &= ~SYMOPT_DEFERRED_LOADS;
  787. }
  788. if ( SymOptions & SYMOPT_NO_CPP ) {
  789. (void)strcat( values, "NO_CPP " );
  790. SymOptions &= ~SYMOPT_NO_CPP;
  791. }
  792. if ( SymOptions & SYMOPT_LOAD_LINES ) {
  793. (void)strcat( values, "LOAD_LINES " );
  794. SymOptions &= ~SYMOPT_LOAD_LINES;
  795. }
  796. if ( SymOptions & SYMOPT_OMAP_FIND_NEAREST ) {
  797. (void)strcat( values, "OMAP_FIND_NEAREST " );
  798. SymOptions &= ~SYMOPT_OMAP_FIND_NEAREST;
  799. }
  800. if ( SymOptions & SYMOPT_DEBUG ) {
  801. (void)strcat( values, "DEBUG " );
  802. SymOptions &= ~SYMOPT_DEBUG;
  803. }
  804. if ( SymOptions ) {
  805. UCHAR uknValues[10];
  806. (void)sprintf( uknValues, "0x%x", SymOptions );
  807. (void)strcat( values, uknValues );
  808. }
  809. return( values );
  810. } // GetSymOptionsValues()
  811. typedef struct _uint64div {
  812. unsigned __int64 quot;
  813. unsigned __int64 rem;
  814. } uint64div_t;
  815. typedef struct _int64div {
  816. __int64 quot;
  817. __int64 rem;
  818. } int64div_t;
  819. void __cdecl UInt64Div (
  820. unsigned __int64 numer,
  821. unsigned __int64 denom,
  822. uint64div_t *result
  823. )
  824. {
  825. assert(result);
  826. if ( denom != (unsigned __int64)0 ) {
  827. result->quot = numer / denom;
  828. result->rem = numer % denom;
  829. }
  830. else {
  831. result->rem = result->quot = (unsigned __int64)0;
  832. }
  833. return;
  834. } // UInt64Div()
  835. void __cdecl Int64Div (
  836. __int64 numer,
  837. __int64 denom,
  838. int64div_t *result
  839. )
  840. {
  841. assert(result);
  842. if ( denom != (__int64)0 ) {
  843. result->quot = numer / denom;
  844. result->rem = numer % denom;
  845. if (numer < 0 && result->rem > 0) {
  846. /* did division wrong; must fix up */
  847. ++result->quot;
  848. result->rem -= denom;
  849. }
  850. }
  851. else {
  852. result->rem = result->quot = (__int64)0;
  853. }
  854. return;
  855. } // Int64Div()
  856. #define UINT64_MAXDWORD ((unsigned __int64)0xffffffff)
  857. unsigned __int64 __cdecl
  858. UInt64PerCent( unsigned __int64 Val, unsigned __int64 Denom )
  859. {
  860. uint64div_t v;
  861. UInt64Div( 100*Val, Denom, &v );
  862. // printf("-%I64d-%I64d-%I64d-", UINT64_MAXDWORD, v.quot, v.rem );
  863. while ( v.rem > UINT64_MAXDWORD ) {
  864. v.quot++;
  865. v.rem -= UINT64_MAXDWORD;
  866. }
  867. // printf("-%I64d-%I64d-%I64d-", UINT64_MAXDWORD, v.quot, v.rem );
  868. return( v.quot );
  869. } // UInt64PerCent()
  870. //////////////////////////////////////////////////
  871. //
  872. // Main
  873. //
  874. int
  875. __cdecl
  876. main (
  877. int argc,
  878. char *argv[]
  879. )
  880. {
  881. DWORD Error;
  882. PMODULE ModuleList;
  883. ULONG ActiveSource=(ULONG)-1;
  884. BOOLEAN Enabled;
  885. SYSTEM_BASIC_INFORMATION BasicInfo;
  886. SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION SystemInfoBegin[32];
  887. SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION SystemInfoEnd[32];
  888. NTSTATUS Status;
  889. TIME_FIELDS Time;
  890. LARGE_INTEGER Elapsed,Idle,Kernel,User;
  891. LARGE_INTEGER TotalElapsed, TotalIdle, TotalKernel, TotalUser;
  892. int i;
  893. PMODULE ZoomModule;
  894. //// Beginning of Program-wide Assertions Section
  895. //
  896. //
  897. //
  898. // This code does not support UNICODE strings
  899. //
  900. #if defined(UNICODE) || defined(_UNICODE)
  901. #error This code does not support UNICODE strings!!!
  902. #endif // UNICODE || _UNICODE
  903. //
  904. //
  905. //// End of Program-wide Assertions Section
  906. //
  907. // Initialize profile source information & SourceMaximum
  908. //
  909. SourceMaximum = InitializeProfileSourceInfo();
  910. if ( ! SourceMaximum ) {
  911. FPRINTF( stderr, "KERNRATE: no profile source detected for this machine...\n" );
  912. return( (int)STATUS_NOT_IMPLEMENTED );
  913. }
  914. //
  915. // Get the default IMAGEHLP global option mask
  916. // NOTE: This global variable could be changed by GetConfigurations().
  917. // It is required to initialize it before calling this function.
  918. //
  919. gSymOptions = SymGetOptions();
  920. if ( Verbose & VERBOSE_IMAGEHLP ) {
  921. FPRINTF( stderr, "KERNRATE: default IMAGEHLP SymOptions: %s\n", GetSymOptionsValues( gSymOptions ) );
  922. }
  923. //
  924. // Get initial parameters
  925. //
  926. GetConfiguration(argc, argv);
  927. //
  928. // Initialize dbghelp
  929. //
  930. // Note that gSymOptions could have been modified in GetConfiguration().
  931. //
  932. SymSetOptions( gSymOptions );
  933. if ( Verbose & VERBOSE_IMAGEHLP ) {
  934. FPRINTF( stderr, "KERNRATE: current IMAGEHLP SymOptions: %s\n", GetSymOptionsValues( gSymOptions ) );
  935. }
  936. Symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
  937. Symbol->MaxNameLength = MAX_SYMNAME_SIZE;
  938. SymInitialize( SymHandle, NULL, FALSE );
  939. if ( SymSetSearchPath(SymHandle, (LPSTR)0 ) == TRUE ) {
  940. // When SymSetSearchPath() is called with SearchPath as NULL, the following
  941. // symbol path default is used:
  942. // .;%_NT_SYMBOL_PATH%;%_NT_ALTERNATE_SYMBOL_PATH%;%WINDIR%
  943. if ( gUserSymbolPath[0] != '\0' ) {
  944. CHAR tmpPath[256];
  945. //
  946. // Note: We prepend the specified path to the current search path.
  947. //
  948. if ( SymGetSearchPath( SymHandle, tmpPath, sizeof( tmpPath ) ) == TRUE ) {
  949. strcpy( gSymbolPath, gUserSymbolPath );
  950. strcat( gSymbolPath, ";");
  951. strcat( gSymbolPath, tmpPath );
  952. if ( SymSetSearchPath( SymHandle, gSymbolPath ) != TRUE ) {
  953. FPRINTF( stderr, "KERNRATE: Failed to set the user specified symbol search path.\nUse default IMAGEHLP symbol search path...\n" );
  954. }
  955. }
  956. }
  957. }
  958. else {
  959. FPRINTF( stderr, "KERNRATE: Failed to set the default symbol search path...\n" );
  960. //
  961. // Set the Symbol Search Path with "%WINDIR%" -
  962. // it was the behaviour of the original MS code...
  963. //
  964. GetEnvironmentVariable("windir", gSymbolPath, sizeof(gSymbolPath));
  965. SymSetSearchPath(SymHandle, gSymbolPath);
  966. }
  967. //
  968. // In any case [and it is redundant to do this in some of the previous cases],
  969. // but we want to be in sync, especially for the image and debug files checksum check.
  970. //
  971. if ( SymGetSearchPath( SymHandle, gSymbolPath, sizeof( gSymbolPath ) ) != TRUE ) {
  972. FPRINTF( stderr, "KERNRATE: Failed to get IMAGEHLP symbol files search path...\n" );
  973. //
  974. // The content of gSymbolPath is now undefined. so clean it...
  975. // gSymbolPath[] users have to check the content.
  976. //
  977. gSymbolPath[0] = '\0';
  978. }
  979. else if ( Verbose & VERBOSE_IMAGEHLP ) {
  980. FPRINTF( stderr, "KERNRATE: IMAGEHLP symbol search path: %s\n", gSymbolPath );
  981. }
  982. //
  983. // Register callbacks for some IMAGEHLP handle operations
  984. //
  985. if ( SymRegisterCallback64( SymHandle, SymbolCallbackFunction, (ULONG64)&gCurrentModule ) != TRUE ) {
  986. FPRINTF( stderr, "KERNRATE: Failed to register callback for IMAGEHLP handle operations...\n" );
  987. }
  988. //
  989. // Get information on kernel / process modules
  990. //
  991. if (SymHandle == (HANDLE)-1) {
  992. ModuleList = GetKernelModuleInformation();
  993. } else {
  994. ModuleList = GetProcessModuleInformation(SymHandle);
  995. }
  996. //
  997. // Any remaining entries on the ZoomList are liable to be errors.
  998. //
  999. ZoomModule = ZoomList;
  1000. while (ZoomModule != NULL) {
  1001. FPRINTF(stderr, "Zoomed module %s not found\n",ZoomModule->module_Name);
  1002. ZoomModule = ZoomModule->Next;
  1003. }
  1004. ZoomList = NULL;
  1005. //
  1006. // Bypass any relevant security
  1007. //
  1008. RtlAdjustPrivilege(SE_SYSTEM_PROFILE_PRIVILEGE,
  1009. TRUE,
  1010. FALSE,
  1011. &Enabled);
  1012. //
  1013. // Create necessary profiles
  1014. //
  1015. CreateProfiles(ModuleList);
  1016. //
  1017. // Set priority up to realtime to minimize timing glitches.
  1018. //
  1019. SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
  1020. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
  1021. //
  1022. // Wait for test to complete.
  1023. //
  1024. SetConsoleCtrlHandler(CtrlcH,TRUE);
  1025. CreateDoneEvent();
  1026. if (SleepInterval == 0) {
  1027. FPRINTF(stderr,"Waiting for ctrl-c\n");
  1028. } else {
  1029. FPRINTF(stderr, "Waiting for %d seconds\n", SleepInterval/1000);
  1030. }
  1031. Status = NtQuerySystemInformation(SystemBasicInformation,
  1032. &BasicInfo,
  1033. sizeof(BasicInfo),
  1034. NULL);
  1035. if (!NT_SUCCESS(Status)) {
  1036. FPRINTF(stderr, "Failed to query basic information %08lx\n",Status);
  1037. exit(Status);
  1038. }
  1039. Status = NtQuerySystemInformation(SystemProcessorPerformanceInformation,
  1040. (PVOID)&SystemInfoBegin,
  1041. sizeof(SystemInfoBegin),
  1042. NULL);
  1043. if (!NT_SUCCESS(Status)) {
  1044. FPRINTF(stderr, "Failed to query starting processor performance information %08lx\n",Status);
  1045. exit(Status);
  1046. }
  1047. do {
  1048. ActiveSource = NextSource(ActiveSource, ModuleList);
  1049. Error = WaitForSingleObject(DoneEvent, ChangeInterval);
  1050. } while ( Error == WAIT_TIMEOUT );
  1051. StopSource(ActiveSource, ModuleList);
  1052. NtQuerySystemInformation(SystemProcessorPerformanceInformation,
  1053. (PVOID)&SystemInfoEnd,
  1054. sizeof(SystemInfoEnd),
  1055. NULL);
  1056. if (!NT_SUCCESS(Status)) {
  1057. FPRINTF(stderr, "Failed to query ending processor performance information %08lx\n",Status);
  1058. exit(Status);
  1059. }
  1060. //
  1061. // Reduce priority
  1062. //
  1063. SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
  1064. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
  1065. SetConsoleCtrlHandler(CtrlcH,FALSE);
  1066. //
  1067. // Restore privilege
  1068. //
  1069. RtlAdjustPrivilege(SE_SYSTEM_PROFILE_PRIVILEGE,
  1070. Enabled,
  1071. FALSE,
  1072. &Enabled);
  1073. //
  1074. // Output time information
  1075. //
  1076. TotalElapsed.QuadPart = 0;
  1077. TotalIdle.QuadPart = 0;
  1078. TotalKernel.QuadPart = 0;
  1079. TotalUser.QuadPart = 0;
  1080. for (i=0; i<BasicInfo.NumberOfProcessors; i++) {
  1081. unsigned __int64 n;
  1082. Idle.QuadPart = SystemInfoEnd[i].IdleTime.QuadPart - SystemInfoBegin[i].IdleTime.QuadPart;
  1083. User.QuadPart = SystemInfoEnd[i].UserTime.QuadPart - SystemInfoBegin[i].UserTime.QuadPart;
  1084. Kernel.QuadPart = SystemInfoEnd[i].KernelTime.QuadPart - SystemInfoBegin[i].KernelTime.QuadPart;
  1085. Elapsed.QuadPart = Kernel.QuadPart + User.QuadPart;
  1086. Kernel.QuadPart -= Idle.QuadPart;
  1087. TotalKernel.QuadPart += Kernel.QuadPart;
  1088. TotalUser.QuadPart += User.QuadPart;
  1089. TotalIdle.QuadPart += Idle.QuadPart;
  1090. TotalElapsed.QuadPart += Elapsed.QuadPart;
  1091. printf("P%d ",i);
  1092. RtlTimeToTimeFields(&Kernel, &Time);
  1093. n = UInt64PerCent( Kernel.QuadPart, Elapsed.QuadPart );
  1094. printf(" K %ld:%02ld:%02ld.%03ld (%3I64u%%)",
  1095. Time.Hour,
  1096. Time.Minute,
  1097. Time.Second,
  1098. Time.Milliseconds,
  1099. n );
  1100. RtlTimeToTimeFields(&User, &Time);
  1101. n = UInt64PerCent( User.QuadPart, Elapsed.QuadPart );
  1102. printf(" U %ld:%02ld:%02ld.%03ld (%3I64u%%)",
  1103. Time.Hour,
  1104. Time.Minute,
  1105. Time.Second,
  1106. Time.Milliseconds,
  1107. n );
  1108. RtlTimeToTimeFields(&Idle, &Time);
  1109. n = UInt64PerCent( Idle.QuadPart, Elapsed.QuadPart );
  1110. printf(" I %ld:%02ld:%02ld.%03ld (%3I64u%%)\n",
  1111. Time.Hour,
  1112. Time.Minute,
  1113. Time.Second,
  1114. Time.Milliseconds,
  1115. n );
  1116. }
  1117. if (BasicInfo.NumberOfProcessors > 1) {
  1118. register int maxprocs = BasicInfo.NumberOfProcessors;
  1119. unsigned __int64 n;
  1120. // ULONG TotalElapsedTime = (ULONG)Elapsed.QuadPart * BasicInfo.NumberOfProcessors;
  1121. printf("TOTAL");
  1122. RtlTimeToTimeFields(&TotalKernel, &Time);
  1123. n = UInt64PerCent( TotalKernel.QuadPart, TotalElapsed.QuadPart );
  1124. printf(" K %ld:%02ld:%02ld.%03ld (%3I64u%%)",
  1125. Time.Hour,
  1126. Time.Minute,
  1127. Time.Second,
  1128. Time.Milliseconds,
  1129. n );
  1130. RtlTimeToTimeFields(&TotalUser, &Time);
  1131. n = UInt64PerCent( TotalUser.QuadPart, TotalElapsed.QuadPart );
  1132. printf(" U %ld:%02ld:%02ld.%03ld (%3I64u%%)",
  1133. Time.Hour,
  1134. Time.Minute,
  1135. Time.Second,
  1136. Time.Milliseconds,
  1137. n );
  1138. RtlTimeToTimeFields(&TotalIdle, &Time);
  1139. n = UInt64PerCent( TotalIdle.QuadPart, TotalElapsed.QuadPart );
  1140. printf(" I %ld:%02ld:%02ld.%03ld (%3I64u%%)\n",
  1141. Time.Hour,
  1142. Time.Minute,
  1143. Time.Second,
  1144. Time.Milliseconds,
  1145. n );
  1146. }
  1147. //
  1148. // Output results
  1149. //
  1150. OutputResults(stdout, ModuleList);
  1151. //
  1152. // Clean up allocated IMAGEHLP resources
  1153. //
  1154. (void)SymCleanup( SymHandle );
  1155. //
  1156. // Normal program exit
  1157. //
  1158. return(0);
  1159. } // main()
  1160. PMODULE
  1161. GetProcessModuleInformation(
  1162. IN HANDLE ProcessHandle
  1163. )
  1164. {
  1165. PROCESS_BASIC_INFORMATION BasicInfo;
  1166. PLIST_ENTRY LdrHead;
  1167. PEB_LDR_DATA Ldr;
  1168. PPEB_LDR_DATA LdrAddress;
  1169. LDR_DATA_TABLE_ENTRY LdrEntry;
  1170. PLDR_DATA_TABLE_ENTRY LdrEntryAddress;
  1171. PLIST_ENTRY LdrNext;
  1172. UNICODE_STRING Pathname;
  1173. WCHAR PathnameBuffer[500];
  1174. UNICODE_STRING fullPathName;
  1175. WCHAR fullPathNameBuffer[_MAX_PATH*sizeof(WCHAR)];
  1176. PEB Peb;
  1177. NTSTATUS Status;
  1178. BOOL Success;
  1179. PMODULE NewModule;
  1180. PMODULE Root=NULL;
  1181. CHAR ModuleName[100];
  1182. CHAR moduleFullName[_MAX_PATH];
  1183. ANSI_STRING AnsiString;
  1184. //
  1185. // Get Peb address.
  1186. //
  1187. Status = NtQueryInformationProcess(ProcessHandle,
  1188. ProcessBasicInformation,
  1189. &BasicInfo,
  1190. sizeof(BasicInfo),
  1191. NULL
  1192. );
  1193. if (!NT_SUCCESS(Status)) {
  1194. FPRINTF(stderr, "NtQueryInformationProcess failed status %08lx\n",Status);
  1195. return NULL;
  1196. }
  1197. if (BasicInfo.PebBaseAddress == NULL) {
  1198. FPRINTF(stderr, "GetProcessModuleInformation: process has no Peb.\n");
  1199. return NULL;
  1200. }
  1201. //
  1202. // Read Peb to get Ldr.
  1203. //
  1204. Success = ReadProcessMemory(ProcessHandle,
  1205. BasicInfo.PebBaseAddress,
  1206. &Peb,
  1207. sizeof(Peb),
  1208. NULL);
  1209. if (!Success) {
  1210. FPRINTF(stderr, "ReadProcessMemory to get the PEB failed, error %d\n", GetLastError());
  1211. return(NULL);
  1212. }
  1213. LdrAddress = Peb.Ldr;
  1214. if (LdrAddress == NULL) {
  1215. FPRINTF(stderr, "Process's LdrAddress is NULL\n");
  1216. return(NULL);
  1217. }
  1218. //
  1219. // Read Ldr to get Ldr entries.
  1220. //
  1221. Success = ReadProcessMemory(ProcessHandle,
  1222. LdrAddress,
  1223. &Ldr,
  1224. sizeof(Ldr),
  1225. NULL);
  1226. if (!Success) {
  1227. FPRINTF(stderr, "ReadProcessMemory to get Ldr entries failed, errror %d\n", GetLastError());
  1228. return(NULL);
  1229. }
  1230. //
  1231. // Read Ldr table entries to get image information.
  1232. //
  1233. if (Ldr.InLoadOrderModuleList.Flink == NULL) {
  1234. FPRINTF(stderr, "Ldr.InLoadOrderModuleList == NULL\n");
  1235. return(NULL);
  1236. }
  1237. LdrHead = &LdrAddress->InLoadOrderModuleList;
  1238. Success = ReadProcessMemory(ProcessHandle,
  1239. &LdrHead->Flink,
  1240. &LdrNext,
  1241. sizeof(LdrNext),
  1242. NULL);
  1243. if (!Success) {
  1244. FPRINTF(stderr, "ReadProcessMemory to get Ldr head failed, errror %d\n", GetLastError());
  1245. return(NULL);
  1246. }
  1247. //
  1248. // Loop through InLoadOrderModuleList.
  1249. //
  1250. while (LdrNext != LdrHead) {
  1251. LdrEntryAddress = CONTAINING_RECORD(LdrNext,
  1252. LDR_DATA_TABLE_ENTRY,
  1253. InLoadOrderLinks);
  1254. Success = ReadProcessMemory(ProcessHandle,
  1255. LdrEntryAddress,
  1256. &LdrEntry,
  1257. sizeof(LdrEntry),
  1258. NULL);
  1259. if (!Success) {
  1260. FPRINTF(stderr, "ReadProcessMemory to get LdrEntry failed, errror %d\n", GetLastError());
  1261. return(NULL);
  1262. }
  1263. //
  1264. // Get copy of image name.
  1265. //
  1266. Pathname = LdrEntry.BaseDllName;
  1267. Pathname.Buffer = &PathnameBuffer[0];
  1268. Success = ReadProcessMemory(ProcessHandle,
  1269. LdrEntry.BaseDllName.Buffer,
  1270. Pathname.Buffer,
  1271. Pathname.MaximumLength,
  1272. NULL);
  1273. if (!Success) {
  1274. FPRINTF(stderr, "ReadProcessMemory to get image name failed, errror %d\n", GetLastError());
  1275. return(NULL);
  1276. }
  1277. //
  1278. // Get Copy of image full pathname
  1279. //
  1280. fullPathName = LdrEntry.FullDllName;
  1281. fullPathName.Buffer = fullPathNameBuffer;
  1282. Success = ReadProcessMemory( ProcessHandle,
  1283. LdrEntry.FullDllName.Buffer,
  1284. fullPathName.Buffer,
  1285. fullPathName.MaximumLength,
  1286. NULL
  1287. );
  1288. //
  1289. // Create module
  1290. //
  1291. AnsiString.Buffer = ModuleName;
  1292. AnsiString.MaximumLength = sizeof(ModuleName);
  1293. AnsiString.Length = 0;
  1294. RtlUnicodeStringToAnsiString(&AnsiString, &Pathname, cDONOT_ALLOCATE_DESTINATION_STRING);
  1295. ModuleName[AnsiString.Length] = '\0';
  1296. AnsiString.Buffer = moduleFullName;
  1297. AnsiString.MaximumLength = sizeof(moduleFullName);
  1298. AnsiString.Length = 0;
  1299. RtlUnicodeStringToAnsiString(&AnsiString, &fullPathName, cDONOT_ALLOCATE_DESTINATION_STRING );
  1300. NewModule = CreateNewModule(ProcessHandle,
  1301. ModuleName,
  1302. moduleFullName,
  1303. (ULONG_PTR)LdrEntry.DllBase,
  1304. LdrEntry.SizeOfImage);
  1305. ModuleCount += 1;
  1306. NewModule->Next = Root;
  1307. Root = NewModule;
  1308. LdrNext = LdrEntry.InLoadOrderLinks.Flink;
  1309. }
  1310. return(Root);
  1311. } // GetProcessModuleInformation()
  1312. PMODULE
  1313. GetKernelModuleInformation(
  1314. VOID
  1315. )
  1316. {
  1317. PRTL_PROCESS_MODULES modules;
  1318. PUCHAR buffer;
  1319. ULONG bufferSize = 32*1024*1024;
  1320. PMODULE root=NULL;
  1321. PMODULE newModule;
  1322. NTSTATUS status;
  1323. ULONG i;
  1324. PLIST_ENTRY ListEntry;
  1325. SYSTEM_BASIC_INFORMATION SystemInformation;
  1326. ULONG_PTR HighestUserAddress;
  1327. while (TRUE) {
  1328. buffer = malloc(bufferSize);
  1329. if (buffer == NULL) {
  1330. FPRINTF(stderr, "Module buffer allocation failed\n");
  1331. exit(0);
  1332. }
  1333. status = NtQuerySystemInformation(SystemModuleInformation,
  1334. buffer,
  1335. bufferSize,
  1336. &bufferSize);
  1337. if (NT_SUCCESS(status)) {
  1338. break;
  1339. }
  1340. if (status == STATUS_INFO_LENGTH_MISMATCH) {
  1341. free(buffer);
  1342. continue;
  1343. }
  1344. }
  1345. status = NtQuerySystemInformation(SystemBasicInformation,
  1346. &SystemInformation,
  1347. sizeof(SystemInformation),
  1348. NULL);
  1349. if (!NT_SUCCESS(status)) {
  1350. FPRINTF(stderr, "NtQuerySystemInformation failed status %08lx\n",status);
  1351. return NULL;
  1352. }
  1353. HighestUserAddress = SystemInformation.MaximumUserModeAddress;
  1354. #ifdef _WIN64
  1355. #define VerboseModuleFormat "start end "
  1356. #else // !_WIN64
  1357. #define VerboseModuleFormat "start end "
  1358. #endif // !_WIN64
  1359. VerbosePrint(( VERBOSE_MODULES, "Kernel Modules ========== System HighestUserAddress = 0x%Ix\n"
  1360. VerboseModuleFormat
  1361. "module name [full name]\n",
  1362. HighestUserAddress
  1363. ));
  1364. #undef VerboseModuleFormat
  1365. modules = (PRTL_PROCESS_MODULES)buffer;
  1366. ModuleCount = modules->NumberOfModules;
  1367. for (i=0; i < ModuleCount; i++) {
  1368. PRTL_PROCESS_MODULE_INFORMATION Module;
  1369. Module = &modules->Modules[i];
  1370. if ((ULONG_PTR)Module->ImageBase > HighestUserAddress) {
  1371. newModule = CreateNewModule(NULL,
  1372. Module->FullPathName+Module->OffsetToFileName,
  1373. Module->FullPathName,
  1374. (ULONG_PTR)Module->ImageBase,
  1375. Module->ImageSize);
  1376. assert( newModule );
  1377. newModule->Next = root;
  1378. root = newModule;
  1379. }
  1380. else {
  1381. #ifdef _WIN64
  1382. #define VerboseModuleFormat "0x%016x 0x%16x "
  1383. #else // !_WIN64
  1384. #define VerboseModuleFormat "0x%08x 0x%08x "
  1385. #endif // !_WIN64
  1386. VerbosePrint(( VERBOSE_MODULES, VerboseModuleFormat " %s [%s] - Base > HighestUserAddress\n",
  1387. (ULONG_PTR)newModule->Base,
  1388. (ULONG_PTR)(newModule->Base + (ULONG64)newModule->Length),
  1389. newModule->module_Name,
  1390. ModuleFullName( newModule )
  1391. ));
  1392. #undef VerboseModuleFormat
  1393. }
  1394. }
  1395. return(root);
  1396. } // GetKernelModuleInformation()
  1397. VOID
  1398. CreateProfiles(
  1399. IN PMODULE Root
  1400. )
  1401. {
  1402. PMODULE Current;
  1403. KPROFILE_SOURCE ProfileSource;
  1404. NTSTATUS Status;
  1405. PRATE_DATA Rate;
  1406. ULONG ProfileSourceIndex;
  1407. for (ProfileSourceIndex=0; ProfileSourceIndex < SourceMaximum != 0; ProfileSourceIndex++) {
  1408. ProfileSource = Source[ProfileSourceIndex].ProfileSource;
  1409. if (Source[ProfileSourceIndex].Interval != 0) {
  1410. Current = Root;
  1411. while (Current != NULL) {
  1412. Rate = &Current->Rate[ProfileSourceIndex];
  1413. Rate->StartTime = 0;
  1414. Rate->TotalTime = 0;
  1415. Rate->TotalCount = 0;
  1416. Rate->CurrentCount = 0;
  1417. if (Current->Zoom) {
  1418. Rate->ProfileBuffer = malloc((Current->Length / ZOOM_BUCKET)*sizeof(ULONG));
  1419. if (Rate->ProfileBuffer == NULL) {
  1420. FPRINTF(stderr,
  1421. "Zoom buffer allocation for %s failed\n",
  1422. Current->module_Name);
  1423. exit(1);
  1424. }
  1425. ZeroMemory(Rate->ProfileBuffer, sizeof(ULONG)*(Current->Length / ZOOM_BUCKET));
  1426. Status = NtCreateProfile(&Rate->ProfileHandle,
  1427. Current->Process,
  1428. (PVOID)Current->Base,
  1429. Current->Length,
  1430. LOG2_ZOOM_BUCKET,
  1431. Rate->ProfileBuffer,
  1432. sizeof(ULONG)*(Current->Length / ZOOM_BUCKET),
  1433. ProfileSource,
  1434. (KAFFINITY)-1);
  1435. if (!NT_SUCCESS(Status)) {
  1436. FPRINTF(stderr,
  1437. "NtCreateProfile on zoomed module %s, source %d failed %08lx\n",
  1438. Current->module_Name,
  1439. ProfileSource,
  1440. Status);
  1441. FPRINTF(stderr,
  1442. "Base %p\nLength %08lx\nBufferLength %08lx\n",
  1443. (PVOID)Current->Base,
  1444. Current->Length,
  1445. Current->Length / ZOOM_BUCKET);
  1446. exit(1);
  1447. }
  1448. else if ( Verbose & VERBOSE_PROFILING ) {
  1449. FPRINTF(stderr,
  1450. "Created zoomed profiling on module %s with source: %s\n",
  1451. Current->module_Name,
  1452. Source[ProfileSourceIndex].ShortName
  1453. );
  1454. }
  1455. } else {
  1456. Status = NtCreateProfile(&Rate->ProfileHandle,
  1457. Current->Process,
  1458. (PVOID)Current->Base,
  1459. Current->Length,
  1460. 31,
  1461. &Rate->CurrentCount,
  1462. sizeof(Rate->CurrentCount),
  1463. ProfileSource,
  1464. (KAFFINITY)-1);
  1465. if (!NT_SUCCESS(Status)) {
  1466. FPRINTF(stderr,
  1467. "NtCreateProfile on module %s, source %d failed %08lx\n",
  1468. Current->module_Name,
  1469. ProfileSource,
  1470. Status);
  1471. exit(1);
  1472. }
  1473. else if ( Verbose & VERBOSE_PROFILING ) {
  1474. FPRINTF(stderr,
  1475. "Created profiling on module %s with source: %s\n",
  1476. Current->module_Name,
  1477. Source[ProfileSourceIndex].ShortName
  1478. );
  1479. }
  1480. }
  1481. Current = Current->Next;
  1482. }
  1483. }
  1484. }
  1485. }
  1486. static void
  1487. SetModuleName( PMODULE Module, PUCHAR szName )
  1488. {
  1489. assert ( Module );
  1490. assert ( szName );
  1491. (void)strncpy( Module->module_Name, szName, sizeof(Module->module_Name) - 1 );
  1492. Module->module_Name[strlen(Module->module_Name)] = '\0';
  1493. return;
  1494. } // SetModuleName()
  1495. VOID
  1496. GetConfiguration(
  1497. int argc,
  1498. char *argv[]
  1499. )
  1500. /*++
  1501. Routine Description:
  1502. Gets configuration for this run.
  1503. Arguments:
  1504. None
  1505. Return Value:
  1506. None, exits on failure.
  1507. --*/
  1508. {
  1509. KPROFILE_SOURCE ProfileSource;
  1510. NTSTATUS Status;
  1511. PMODULE ZoomModule;
  1512. DWORD Pid;
  1513. int i;
  1514. ULONG ProfileSourceIndex;
  1515. for (i=1; i < argc; i++) {
  1516. if ((argv[i][0] == '-') || (argv[i][0] == '/')) {
  1517. switch ( toupper(argv[i][1]) ) {
  1518. case 'B':
  1519. //
  1520. // Set Zoom Bucket Size
  1521. //
  1522. if (++i == argc) {
  1523. FPRINTF(stderr,
  1524. "KERNRATE: '-b N' option requires bucket size\n");
  1525. Usage();
  1526. }
  1527. ZOOM_BUCKET = (ULONG)atoi(argv[i]);
  1528. if (ZOOM_BUCKET == 0) {
  1529. FPRINTF(stderr,
  1530. "KERNRATE: Invalid option '-b %s'\n",
  1531. argv[i]);
  1532. Usage();
  1533. }
  1534. for (LOG2_ZOOM_BUCKET=1; (1UL<<LOG2_ZOOM_BUCKET) < ZOOM_BUCKET; LOG2_ZOOM_BUCKET++)
  1535. // Empty Loop
  1536. ;
  1537. if (ZOOM_BUCKET != (1UL<<LOG2_ZOOM_BUCKET)) {
  1538. FPRINTF(stderr,
  1539. "KERNRATE: Bucket size must be power of 2\n");
  1540. Usage();
  1541. }
  1542. break;
  1543. case 'C':
  1544. //
  1545. // Set change interval.
  1546. //
  1547. if (++i == argc) {
  1548. FPRINTF(stderr,
  1549. "KERNRATE: '-c N' option requires milliseconds\n");
  1550. Usage();
  1551. }
  1552. ChangeInterval = atoi(argv[i]);
  1553. if (ChangeInterval == 0) {
  1554. FPRINTF(stderr,
  1555. "KERNRATE: Invalid option '-c %s'\n",
  1556. argv[i]);
  1557. Usage();
  1558. }
  1559. break;
  1560. case 'D':
  1561. //
  1562. // Output data rounding up and down
  1563. //
  1564. RoundingVerboseOutput = TRUE;
  1565. break;
  1566. case 'I':
  1567. {
  1568. BOOLEAN found;
  1569. ULONG rate;
  1570. if ( ++i == argc ) {
  1571. FPRINTF(stderr, "KERNRATE: '-i' option requires at least a rate value\n");
  1572. Usage();
  1573. }
  1574. //
  1575. // The user can specify '-i' with a rate only.
  1576. // In this case, SOURCE_TIME is used.
  1577. //
  1578. if ( !isalpha( argv[i][0] ) ) {
  1579. rate = (ULONG)atol(argv[i]);
  1580. if (rate == 0) {
  1581. FPRINTF(stderr,
  1582. "KERNRATE: Invalid option '-i %s'\n",
  1583. argv[i]);
  1584. Usage();
  1585. }
  1586. Source[SOURCE_TIME].Interval = rate;
  1587. break;
  1588. }
  1589. //
  1590. // Standard option processing:
  1591. // the source shortname string is specified.
  1592. //
  1593. if ( (i + 1) == argc ) {
  1594. FPRINTF(stderr, "KERNRATE: '-i' option requires a source and a rate\n");
  1595. Usage();
  1596. }
  1597. found = FALSE;
  1598. for ( ProfileSourceIndex = 0; ProfileSourceIndex < SourceMaximum; ProfileSourceIndex++) {
  1599. if ( !_stricmp(Source[ProfileSourceIndex].ShortName, argv[i]) ) {
  1600. rate = (ULONG)atol(argv[i + 1]);
  1601. Source[ProfileSourceIndex].Interval = rate;
  1602. found = TRUE;
  1603. i++;
  1604. }
  1605. }
  1606. if ( found == FALSE) {
  1607. FPRINTF(stderr,
  1608. "KERNRATE: Invalid source name %s.\nRun KERNRATE with the '-l' option to list supported sources.\n", argv[i] );
  1609. Usage();
  1610. }
  1611. }
  1612. break;
  1613. case 'J':
  1614. //
  1615. // User specified symbol search path.
  1616. // It is going to be prepend to the default image help symbol search path.
  1617. //
  1618. if (++i == argc) {
  1619. FPRINTF(stderr,
  1620. "KERNRATE: '-j SymbolPath' option requires SymbolPath\n");
  1621. Usage();
  1622. }
  1623. strncpy( gUserSymbolPath, argv[i], sizeof( gUserSymbolPath ) - 1);
  1624. break;
  1625. case 'L':
  1626. {
  1627. PSOURCE src;
  1628. printf("List of profile sources supported for this platform:\n\n");
  1629. printf("%*s - %-*s - %-10s\n\n", DescriptionMaxLen, "Name", TokenMaxLen, "ShortName", "Interval");
  1630. //
  1631. // Print the possible static sources.
  1632. // static in the sense of NT KE fixed sources.
  1633. //
  1634. for ( ProfileSourceIndex = 0; ProfileSourceIndex < ProfileMaximum; ProfileSourceIndex++ ) {
  1635. src = &Source[ProfileSourceIndex];
  1636. //
  1637. // Display the supported profile sources, only.
  1638. //
  1639. if ( src->DesiredInterval ) {
  1640. printf( "%*s - %-*s - %-10ld\n", DescriptionMaxLen,
  1641. src->Name,
  1642. TokenMaxLen,
  1643. src->ShortName,
  1644. src->DesiredInterval
  1645. );
  1646. }
  1647. }
  1648. //
  1649. // Print the possible dynamic sources.
  1650. //
  1651. while( ProfileSourceIndex < SourceMaximum ) {
  1652. src = &Source[ProfileSourceIndex];
  1653. //
  1654. // Display the supported profile sources, only.
  1655. //
  1656. if ( src->DesiredInterval ) {
  1657. printf( "%*s - %-*s - %-10ld\n", DescriptionMaxLen,
  1658. src->Name,
  1659. TokenMaxLen,
  1660. src->ShortName,
  1661. src->DesiredInterval
  1662. );
  1663. }
  1664. ProfileSourceIndex++;
  1665. }
  1666. //
  1667. // If the user specified '-lx', we exit immediately.
  1668. //
  1669. if ( ( argv[i][2] == 'x' ) || ( argv[i][2] == 'X' )) {
  1670. exit(0);
  1671. }
  1672. printf("\n");
  1673. }
  1674. break;
  1675. case 'P':
  1676. //
  1677. // Monitor given process instead of kernel
  1678. //
  1679. if (++i == argc) {
  1680. FPRINTF(stderr,
  1681. "KERNRATE: '-p processid' option requires a process id\n");
  1682. Usage();
  1683. }
  1684. Pid = atoi(argv[i]);
  1685. SymHandle = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION,
  1686. FALSE,
  1687. Pid);
  1688. if (SymHandle==NULL) {
  1689. FPRINTF(stderr, "KERNRATE: OpenProcess(%d) failed %d\n",Pid,GetLastError());
  1690. exit(0);
  1691. }
  1692. break;
  1693. case 'R':
  1694. //
  1695. // Turn on RAW bucket dump
  1696. //
  1697. RawData = TRUE;
  1698. //
  1699. // If the user specified '-rd', we want to output disassembly with the raw data.
  1700. //
  1701. if ( ( argv[i][2] == 'd' ) || ( argv[i][2] == 'D' )) {
  1702. RawDisasm = TRUE;
  1703. }
  1704. break;
  1705. case 'S':
  1706. //
  1707. // Set Sleep interval
  1708. //
  1709. if (++i == argc) {
  1710. FPRINTF(stderr,
  1711. "KERNRATE: '-s N' option requires seconds\n");
  1712. Usage();
  1713. }
  1714. SleepInterval = atoi(argv[i]) * 1000;
  1715. if (SleepInterval == 0) {
  1716. FPRINTF(stderr,
  1717. "KERNRATE: Invalid option '-s %s'\n",
  1718. argv[i]);
  1719. Usage();
  1720. }
  1721. break;
  1722. case 'U':
  1723. //
  1724. // Requests IMAGEHLP to present undecorated symbol names
  1725. //
  1726. gSymOptions |= SYMOPT_UNDNAME;
  1727. break;
  1728. case 'V':
  1729. //
  1730. // Verbose mode.
  1731. //
  1732. Verbose = VERBOSE_DEFAULT;
  1733. if ( ((i+1) < argc) && (argv[i+1][0] != '-') ) {
  1734. i++;
  1735. Verbose = atoi(argv[i]);
  1736. }
  1737. if ( Verbose & VERBOSE_IMAGEHLP ) {
  1738. gSymOptions |= SYMOPT_DEBUG;
  1739. }
  1740. break;
  1741. case 'Z':
  1742. if (++i == argc) {
  1743. FPRINTF(stderr,
  1744. "KERNRATE: '-z modulename' option requires modulename\n");
  1745. Usage();
  1746. }
  1747. ZoomModule = calloc(1, sizeof(MODULE)+sizeof(RATE_DATA)*SourceMaximum);
  1748. if (ZoomModule==NULL) {
  1749. FPRINTF(stderr, "Allocation of zoom module %s failed\n",argv[i]);
  1750. exit(1);
  1751. }
  1752. SetModuleName( ZoomModule, argv[i] );
  1753. ZoomModule->Zoom = TRUE;
  1754. ZoomModule->Next = ZoomList;
  1755. ZoomList = ZoomModule;
  1756. break;
  1757. case '?':
  1758. //
  1759. // Print Usage string and exits
  1760. //
  1761. Usage();
  1762. break;
  1763. default:
  1764. //
  1765. // Specify the unknown option and print the Usage string. Then exists.
  1766. //
  1767. FPRINTF(stderr,
  1768. "KERNRATE: Unknown option %s\n",argv[i]);
  1769. Usage();
  1770. break;
  1771. }
  1772. } else {
  1773. FPRINTF(stderr,
  1774. "KERNRATE: Invalid switch %s\n",argv[i]);
  1775. Usage();
  1776. }
  1777. }
  1778. //
  1779. // Determine supported sources
  1780. //
  1781. for (ProfileSourceIndex = 0; ProfileSourceIndex < SourceMaximum; ProfileSourceIndex++) {
  1782. if ( Source[ProfileSourceIndex].DesiredInterval && Source[ProfileSourceIndex].Interval ) {
  1783. ULONG ThisInterval;
  1784. ProfileSource = Source[ProfileSourceIndex].ProfileSource;
  1785. NtSetIntervalProfile(Source[ProfileSourceIndex].DesiredInterval, ProfileSource);
  1786. Status = NtQueryIntervalProfile(ProfileSource, &ThisInterval);
  1787. if ((NT_SUCCESS(Status)) && (ThisInterval > 0)) {
  1788. printf("Recording %s at %d events/hit\n", Source[ProfileSourceIndex].Name, ThisInterval);
  1789. Source[ProfileSourceIndex].Interval = ThisInterval;
  1790. } else {
  1791. Source[ProfileSourceIndex].Interval = 0;
  1792. }
  1793. }
  1794. else {
  1795. Source[ProfileSourceIndex].Interval = 0;
  1796. }
  1797. }
  1798. return;
  1799. } /* GetConfiguration() */
  1800. PSOURCE
  1801. InitializeStaticSources(
  1802. VOID
  1803. )
  1804. {
  1805. #if defined(_IA64_)
  1806. NTSTATUS status;
  1807. SYSTEM_PROCESSOR_INFORMATION sysProcInfo;
  1808. status = NtQuerySystemInformation( SystemProcessorInformation,
  1809. &sysProcInfo,
  1810. sizeof(SYSTEM_PROCESSOR_INFORMATION),
  1811. NULL);
  1812. if (NT_SUCCESS(status) && (sysProcInfo.ProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) ) {
  1813. switch( sysProcInfo.ProcessorLevel ) {
  1814. case IA64_MERCED:
  1815. {
  1816. //
  1817. // Patch the last entry as defined with convention used to initialize
  1818. // SourceMaximum.
  1819. //
  1820. ULONG n = sizeof(mercedStaticSources)/sizeof(mercedStaticSources[0]);
  1821. mercedStaticSources[n-1].Name = NULL;
  1822. mercedStaticSources[n-1].ShortName = "";
  1823. }
  1824. return mercedStaticSources;
  1825. break;
  1826. case IA64_MCKINLEY:
  1827. // Thierry - 02/08/2000 - use default for now.
  1828. break;
  1829. }
  1830. }
  1831. //
  1832. // NtQuerySystemInformation() failure and default case:
  1833. //
  1834. #endif // _IA64_
  1835. return StaticSources;
  1836. } // InitializeStaticSources()
  1837. ULONG
  1838. InitializeProfileSourceInfo (
  1839. VOID
  1840. )
  1841. /*++
  1842. Function Description:
  1843. This function initializes the Profile sources.
  1844. Argument:
  1845. None.
  1846. Return Value:
  1847. None.
  1848. Algorithm:
  1849. ToBeSpecified
  1850. In/Out Conditions:
  1851. ToBeSpecified
  1852. Globals Referenced:
  1853. ToBeSpecified
  1854. Exception Conditions:
  1855. ToBeSpecified
  1856. MP Conditions:
  1857. ToBeSpecified
  1858. Notes:
  1859. This function has been enhanced from its original version
  1860. to support and use the static profiling sources even if the
  1861. pstat driver is not present or returned no active profiling
  1862. event.
  1863. ToDo List:
  1864. ToBeSpecified
  1865. Modification History:
  1866. 3/17/2000 TF Initial version
  1867. --*/
  1868. {
  1869. UNICODE_STRING DriverName;
  1870. NTSTATUS status;
  1871. OBJECT_ATTRIBUTES ObjA;
  1872. IO_STATUS_BLOCK IOSB;
  1873. UCHAR buffer[400];
  1874. ULONG i, j;
  1875. PEVENTID Event;
  1876. HANDLE DriverHandle;
  1877. PEVENTS_INFO eventInfo;
  1878. PSOURCE staticSource, src;
  1879. ULONG staticCount, driverCount, totalCount;
  1880. //
  1881. // Initializations
  1882. //
  1883. DriverHandle = INVALID_HANDLE_VALUE;
  1884. staticCount = driverCount = 0;
  1885. //
  1886. // Open PStat driver
  1887. //
  1888. RtlInitUnicodeString(&DriverName, L"\\Device\\PStat");
  1889. InitializeObjectAttributes(
  1890. &ObjA,
  1891. &DriverName,
  1892. OBJ_CASE_INSENSITIVE,
  1893. 0,
  1894. 0 );
  1895. status = NtOpenFile (
  1896. &DriverHandle, // return handle
  1897. SYNCHRONIZE | FILE_READ_DATA, // desired access
  1898. &ObjA, // Object
  1899. &IOSB, // io status block
  1900. FILE_SHARE_READ | FILE_SHARE_WRITE, // share access
  1901. FILE_SYNCHRONOUS_IO_ALERT // open options
  1902. );
  1903. if ( NT_SUCCESS(status) ) {
  1904. //
  1905. // Determine how many events the driver provides
  1906. //
  1907. eventInfo = (PEVENTS_INFO)buffer;
  1908. status = NtDeviceIoControlFile( DriverHandle,
  1909. (HANDLE) NULL, // event
  1910. (PIO_APC_ROUTINE) NULL,
  1911. (PVOID) NULL,
  1912. &IOSB,
  1913. PSTAT_QUERY_EVENTS_INFO,
  1914. buffer, // input buffer
  1915. sizeof (buffer),
  1916. NULL, // output buffer
  1917. 0
  1918. );
  1919. driverCount = eventInfo->Events;
  1920. if ( NT_SUCCESS(status) && driverCount ) {
  1921. if ( eventInfo->TokenMaxLength > TokenMaxLen ) {
  1922. TokenMaxLen = eventInfo->TokenMaxLength;
  1923. }
  1924. if ( eventInfo->DescriptionMaxLength > DescriptionMaxLen ) {
  1925. DescriptionMaxLen = eventInfo->DescriptionMaxLength;
  1926. }
  1927. }
  1928. }
  1929. //
  1930. // Determine how many static events there are and
  1931. // re-initialize the format specifiers if needed.
  1932. //
  1933. src = staticSource = InitializeStaticSources();
  1934. assert( staticSource );
  1935. while( src->Name != NULL ) {
  1936. if ( strlen( src->Name ) > DescriptionMaxLen ) {
  1937. DescriptionMaxLen = strlen( src->Name );
  1938. }
  1939. if ( strlen( src->ShortName ) > TokenMaxLen ) {
  1940. TokenMaxLen = strlen( src->ShortName );
  1941. }
  1942. staticCount++;
  1943. src++;
  1944. }
  1945. //
  1946. // Allocate memory for static events, plus the driver
  1947. // provided events
  1948. //
  1949. totalCount = driverCount + staticCount;
  1950. Source = malloc(sizeof(SOURCE) * totalCount);
  1951. if ( Source == NULL ) {
  1952. FPRINTF(stderr, "KERNRATE: Events memory allocation failed\n" );
  1953. if ( IsValidHandle( DriverHandle ) ) {
  1954. NtClose (DriverHandle);
  1955. }
  1956. exit(1);
  1957. }
  1958. ZeroMemory (Source, sizeof(SOURCE) * totalCount);
  1959. //
  1960. // copy static events to new list
  1961. //
  1962. for (j=0; j < staticCount; j++) {
  1963. Source[j] = staticSource[j];
  1964. }
  1965. //
  1966. // Append the driver provided events to new list
  1967. //
  1968. if ( IsValidHandle( DriverHandle ) ) {
  1969. Event = (PEVENTID) buffer;
  1970. for (i=0; i < driverCount; i++) {
  1971. *((PULONG) buffer) = i;
  1972. NtDeviceIoControlFile(
  1973. DriverHandle,
  1974. (HANDLE) NULL, // event
  1975. (PIO_APC_ROUTINE) NULL,
  1976. (PVOID) NULL,
  1977. &IOSB,
  1978. PSTAT_QUERY_EVENTS,
  1979. buffer, // input buffer
  1980. sizeof (buffer),
  1981. NULL, // output buffer
  1982. 0
  1983. );
  1984. //
  1985. // Source Names:
  1986. // - For the Name, we use the description
  1987. // - For the short Name, we use the token string stored
  1988. // in the first string of the buffer
  1989. //
  1990. Source[j].Name = _strdup (Event->Buffer + Event->DescriptionOffset);
  1991. Source[j].ShortName = _strdup(Event->Buffer);
  1992. Source[j].ProfileSource = Event->ProfileSource;
  1993. Source[j].DesiredInterval = Event->SuggestedIntervalBase;
  1994. j++;
  1995. }
  1996. NtClose (DriverHandle);
  1997. }
  1998. return( totalCount );
  1999. } // InitializeProfileSourceInfo()
  2000. ULONG
  2001. NextSource(
  2002. IN ULONG CurrentSource,
  2003. IN PMODULE ModuleList
  2004. )
  2005. /*++
  2006. Routine Description:
  2007. Stops the current profile source and starts the next one.
  2008. If a CurrentSource of -1 is passed in, no source will
  2009. be stopped and the first active source will be started.
  2010. Arguments:
  2011. CurrentSource - Supplies the current profile source
  2012. ModuleList - Supplies the list of modules whose soruces are to be changed
  2013. Return Value:
  2014. Returns the new current profile source
  2015. --*/
  2016. {
  2017. if (CurrentSource != (ULONG) -1) {
  2018. StopSource(CurrentSource, ModuleList);
  2019. }
  2020. //
  2021. // Iterate through the available sources to find the
  2022. // next active source to be started.
  2023. //
  2024. do {
  2025. if (CurrentSource == (ULONG) -1) {
  2026. CurrentSource = 0;
  2027. } else {
  2028. CurrentSource = CurrentSource+1;
  2029. if (CurrentSource == SourceMaximum) {
  2030. CurrentSource = 0;
  2031. }
  2032. }
  2033. } while ( Source[CurrentSource].Interval == 0);
  2034. StartSource(CurrentSource,ModuleList);
  2035. return(CurrentSource);
  2036. }
  2037. VOID
  2038. StopSource(
  2039. IN ULONG ProfileSourceIndex,
  2040. IN PMODULE ModuleList
  2041. )
  2042. /*++
  2043. Routine Description:
  2044. Stops all profile objects for a given source
  2045. Arguments:
  2046. ProfileSource - Supplies the source to be stopped.
  2047. ModuleList - Supplies the list of modules whose profiles are to be stopped
  2048. Return Value:
  2049. None.
  2050. --*/
  2051. {
  2052. PMODULE Current;
  2053. NTSTATUS Status;
  2054. ULONGLONG StopTime;
  2055. ULONGLONG ElapsedTime;
  2056. Current = ModuleList;
  2057. while (Current != NULL) {
  2058. Status = NtStopProfile(Current->Rate[ProfileSourceIndex].ProfileHandle);
  2059. GetSystemTimeAsFileTime((LPFILETIME)&StopTime);
  2060. if (!NT_SUCCESS(Status)) {
  2061. FPRINTF(stderr,
  2062. "NtStopProfile on source %s failed, %08lx\n",
  2063. Source[ProfileSourceIndex].Name,
  2064. Status);
  2065. } else {
  2066. ElapsedTime = StopTime - Current->Rate[ProfileSourceIndex].StartTime;
  2067. Current->Rate[ProfileSourceIndex].TotalTime += ElapsedTime;
  2068. Current->Rate[ProfileSourceIndex].TotalCount += Current->Rate[ProfileSourceIndex].CurrentCount;
  2069. Current->Rate[ProfileSourceIndex].CurrentCount = 0;
  2070. }
  2071. Current = Current->Next;
  2072. }
  2073. }
  2074. VOID
  2075. StartSource(
  2076. IN ULONG ProfileSourceIndex,
  2077. IN PMODULE ModuleList
  2078. )
  2079. /*++
  2080. Routine Description:
  2081. Starts all profile objects for a given source
  2082. Arguments:
  2083. ProfileSource - Supplies the source to be started.
  2084. ModuleList - Supplies the list of modules whose profiles are to be stopped
  2085. Return Value:
  2086. None.
  2087. --*/
  2088. {
  2089. PMODULE Current;
  2090. NTSTATUS Status;
  2091. ULONGLONG StopTime;
  2092. ULONGLONG ElapsedTime;
  2093. Current = ModuleList;
  2094. while (Current != NULL) {
  2095. GetSystemTimeAsFileTime((LPFILETIME)&Current->Rate[ProfileSourceIndex].StartTime);
  2096. Status = NtStartProfile(Current->Rate[ProfileSourceIndex].ProfileHandle);
  2097. if (!NT_SUCCESS(Status)) {
  2098. FPRINTF(stderr,
  2099. "NtStartProfile on source %s failed, %08lx\n",
  2100. Source[ProfileSourceIndex].Name,
  2101. Status);
  2102. }
  2103. Current = Current->Next;
  2104. }
  2105. }
  2106. VOID
  2107. OutputResults(
  2108. IN FILE *Out,
  2109. IN PMODULE ModuleList
  2110. )
  2111. /*++
  2112. Routine Description:
  2113. Outputs the collected data.
  2114. Arguments:
  2115. Out - Supplies the FILE * where the output should go.
  2116. ModuleList - Supplies the list of modules to output
  2117. Return Value:
  2118. None.
  2119. --*/
  2120. {
  2121. PMODULE Current;
  2122. PRATE_DATA RateData;
  2123. ULONG i, j, ProfileSourceIndex;
  2124. ULONG RoundDown;
  2125. //
  2126. // Sum up the total buffers of any zoomed modules
  2127. //
  2128. Current = ModuleList;
  2129. while (Current != NULL) {
  2130. if (Current->Zoom) {
  2131. for (ProfileSourceIndex=0; ProfileSourceIndex < SourceMaximum; ProfileSourceIndex++) {
  2132. if (Source[ProfileSourceIndex].Interval != 0) {
  2133. //
  2134. // Sum the entire profile buffer for this module/source
  2135. //
  2136. RateData = &Current->Rate[ProfileSourceIndex];
  2137. RateData->TotalCount = 0;
  2138. for (i=0; i < Current->Length/ZOOM_BUCKET; i++) {
  2139. RateData->TotalCount += RateData->ProfileBuffer[i];
  2140. }
  2141. }
  2142. }
  2143. }
  2144. Current = Current->Next;
  2145. }
  2146. //
  2147. // Output the results ordered by profile source.
  2148. //
  2149. OutputModuleList(Out, ModuleList, ModuleCount);
  2150. //
  2151. // For any zoomed modules, create and output a module list
  2152. // consisting of the functions in the module.
  2153. //
  2154. Current = ModuleList;
  2155. while (Current != NULL) {
  2156. if (Current->Zoom) {
  2157. ZoomCount = 0;
  2158. ZoomList = NULL;
  2159. for (RoundDown = 0; RoundDown <= (RoundingVerboseOutput ? 1UL:0UL); RoundDown++) {
  2160. CreateZoomedModuleList(Current,RoundDown);
  2161. if (ZoomList == NULL) {
  2162. FPRINTF(stderr, "No symbols found for module %s\n",Current->module_Name);
  2163. } else {
  2164. PMODULE Temp;
  2165. FPRINTF(Out, "\n----- Zoomed module %s (Bucket size = %d bytes, Rounding %s) --------\n",
  2166. Current->module_Name,
  2167. ZOOM_BUCKET,
  2168. (RoundDown ? "Up" : "Down" ) );
  2169. OutputModuleList(Out, ZoomList, ZoomCount);
  2170. Temp = ZoomList;
  2171. while (Temp != NULL) {
  2172. ZoomList = ZoomList->Next;
  2173. free(Temp);
  2174. Temp = ZoomList;
  2175. }
  2176. }
  2177. }
  2178. }
  2179. Current = Current->Next;
  2180. }
  2181. if (RawData) {
  2182. //
  2183. // Display the raw bucket counts for all zoomed modules
  2184. //
  2185. Current = ModuleList;
  2186. while (Current != NULL) {
  2187. if (Current->Zoom) {
  2188. for (ProfileSourceIndex=0; ProfileSourceIndex < SourceMaximum; ProfileSourceIndex++) {
  2189. if (Source[ProfileSourceIndex].Interval != 0) {
  2190. FPRINTF(Out,
  2191. "\n---- RAW %s Profile Source %s\n",
  2192. Current->module_Name,
  2193. Source[ProfileSourceIndex].Name);
  2194. RateData = &Current->Rate[ProfileSourceIndex];
  2195. for (i=0; i < (Current->Length/ZOOM_BUCKET) ; i++) {
  2196. ULONG hits = RateData->ProfileBuffer[i];
  2197. if ( hits > 0 ) {
  2198. // TF - FIXFIX - 07/2000.
  2199. // The current version of kernrate and kernel profiling objects code
  2200. // assume code section < 4GB.
  2201. //
  2202. ULONG64 ip = Current->Base + (ULONG64)(i * ZOOM_BUCKET);
  2203. ULONG64 disp = 0;
  2204. if ( !SymGetSymFromAddr64(SymHandle, ip, &disp, Symbol ) ) {
  2205. FPRINTF( stderr, "No symbol found for bucket at 0x%I64x\n", ip );
  2206. }
  2207. else {
  2208. CHAR symName[80];
  2209. ULONG64 ipMax;
  2210. _snprintf( symName, 80, "%s+0x%I64x[0x%I64x]", Symbol->Name, disp, ip );
  2211. if ( RawDisasm ) {
  2212. CHAR sourceCode[320];
  2213. #ifndef DISASM_AVAILABLE
  2214. // Thierry - FIXFIX - 07/2000.
  2215. // dbg is not helping... The old disassembly APIs no longer work.
  2216. // I have to re-write a full disassembly wrapper.
  2217. #define Disasm( IpAddr, Buffer, Flag ) 0
  2218. #endif // !DISASM_AVAILABLE
  2219. if ( Disasm( &ip, sourceCode, FALSE ) ) {
  2220. FPRINTF( Out,"%-40s %10d %s\n", symName, hits, sourceCode );
  2221. }
  2222. else {
  2223. FPRINTF( Out,"%-40s %10d <disasm:?????>\n", symName, hits );
  2224. }
  2225. }
  2226. else {
  2227. FPRINTF( Out,"%-40s %10d\n", symName, hits );
  2228. }
  2229. //
  2230. // Print other symbols in this bucket by incrementing
  2231. // by 2 bytes at a time.
  2232. //
  2233. ipMax = ip + (ULONG64)ZOOM_BUCKET;
  2234. ip += (ULONG64)2;
  2235. while( ip < ipMax ) {
  2236. UCHAR lastSym[80];
  2237. strcpy( lastSym, Symbol->Name );
  2238. if ( SymGetSymFromAddr64(SymHandle, ip, &disp , Symbol ) ) {
  2239. if ( strcmp( lastSym,Symbol->Name ) ) {
  2240. FPRINTF( Out, " %s+0x%I64x[0x%I64x]\n", Symbol->Name, disp, ip );
  2241. strcpy( lastSym,Symbol->Name );
  2242. }
  2243. }
  2244. ip += (ULONG64)2;
  2245. } // End of while( ip < ipMax )
  2246. }
  2247. }
  2248. }
  2249. }
  2250. }
  2251. }
  2252. Current = Current->Next;
  2253. }
  2254. }
  2255. return;
  2256. } // OutputResults()
  2257. BOOL
  2258. CreateZoomModuleCallback(
  2259. IN LPSTR szSymName,
  2260. IN ULONG64 Address,
  2261. IN ULONG Size,
  2262. IN PVOID Cxt
  2263. )
  2264. {
  2265. PMODULE Module;
  2266. PRATE_DATA RateData;
  2267. ULONG64 i, StartIndex, EndIndex;
  2268. ULONG ProfileSourceIndex;
  2269. BOOLEAN HasHits;
  2270. Module = calloc(1, sizeof(MODULE)+sizeof(RATE_DATA)*SourceMaximum);
  2271. if (Module == NULL) {
  2272. FPRINTF(stderr, "CreateZoomModuleCallback: failed to allocate Zoom module\n");
  2273. exit(1);
  2274. }
  2275. Module->Base = Address;
  2276. Module->Length = Size;
  2277. Module->Zoom = FALSE;
  2278. SetModuleName( Module, szSymName );
  2279. //
  2280. // Compute range in profile buffer to sum.
  2281. //
  2282. StartIndex = (ULONG)((Module->Base - CallbackCurrent->Base) / ZOOM_BUCKET);
  2283. #ifdef BUGBUG
  2284. EndIndex = StartIndex + (Module->Length / ZOOM_BUCKET);
  2285. #else
  2286. EndIndex = (Module->Base + Module->Length - CallbackCurrent->Base) / ZOOM_BUCKET;
  2287. #endif
  2288. HasHits = FALSE;
  2289. for (ProfileSourceIndex=0; ProfileSourceIndex < SourceMaximum; ProfileSourceIndex++) {
  2290. if (Source[ProfileSourceIndex].Interval != 0) {
  2291. RateData = &Module->Rate[ProfileSourceIndex];
  2292. RateData->StartTime = CallbackCurrent->Rate[ProfileSourceIndex].StartTime;
  2293. RateData->TotalTime = CallbackCurrent->Rate[ProfileSourceIndex].TotalTime;
  2294. RateData->TotalCount = 0;
  2295. RateData->ProfileHandle = NULL;
  2296. RateData->CurrentCount = 0;
  2297. RateData->ProfileBuffer = NULL;
  2298. for (i=StartIndex; i < EndIndex; i++) {
  2299. RateData->TotalCount += CallbackCurrent->Rate[ProfileSourceIndex].ProfileBuffer[i];
  2300. }
  2301. if (RateData->TotalCount > 0) {
  2302. HasHits = TRUE;
  2303. }
  2304. }
  2305. }
  2306. //
  2307. // If the routine has hits add it to the list, otherwise
  2308. // ignore it.
  2309. //
  2310. if (HasHits) {
  2311. Module->Next = ZoomList;
  2312. ZoomList = Module;
  2313. ++ZoomCount;
  2314. } else {
  2315. free(Module);
  2316. }
  2317. return(TRUE);
  2318. }
  2319. /* BEGIN_IMS TkEnumerateSymbols
  2320. ******************************************************************************
  2321. ****
  2322. **** TkEnumerateSymbols ( )
  2323. ****
  2324. ******************************************************************************
  2325. *
  2326. * Function Description:
  2327. *
  2328. * Calls the specified function for every symbol in the Current module.
  2329. * The algorithm results in a round-up behavior for the output --
  2330. * for each bucket, the symbol corresponding to the first byte of the
  2331. * bucket is used.
  2332. *
  2333. * Arguments:
  2334. *
  2335. * IN HANDLE SymHandle : ImageHelp handle
  2336. *
  2337. * IN PMODULE Current : Pointer to current module structure
  2338. *
  2339. * IN PSYM_ENUMSYMBOLS_CALLBACK EnumSymbolsCallback : Routine to call for each symbol
  2340. *
  2341. * Return Value:
  2342. *
  2343. * BOOL
  2344. *
  2345. * Algorithm:
  2346. *
  2347. * ToBeSpecified
  2348. *
  2349. * Globals Referenced:
  2350. *
  2351. * ToBeSpecified
  2352. *
  2353. * Exception Conditions:
  2354. *
  2355. * ToBeSpecified
  2356. *
  2357. * In/Out Conditions:
  2358. *
  2359. * ToBeSpecified
  2360. *
  2361. * Notes:
  2362. *
  2363. * ToBeSpecified
  2364. *
  2365. * ToDo List:
  2366. *
  2367. * ToBeSpecified
  2368. *
  2369. * Modification History:
  2370. *
  2371. * 9/5/97 TF Initial version
  2372. *
  2373. ******************************************************************************
  2374. * END_IMS TkEnumerateSymbols */
  2375. BOOL
  2376. TkEnumerateSymbols(
  2377. IN HANDLE SymHandle,
  2378. IN PMODULE Current,
  2379. IN PSYM_ENUMSYMBOLS_CALLBACK64 EnumSymbolsCallback
  2380. )
  2381. {
  2382. UCHAR CurrentSym[80];
  2383. DWORD64 CurrentAddr = 0;
  2384. ULONG i;
  2385. DWORD64 Displacement;
  2386. CurrentSym[0] = '\0';
  2387. for (i=0; i<Current->Length/ZOOM_BUCKET; i++) {
  2388. // Check if this bucket will be assigned to a different symbol...
  2389. if (SymGetSymFromAddr64(SymHandle, Current->Base+i*ZOOM_BUCKET, &Displacement, Symbol )) {
  2390. // It will... Invoke the callback for the old one
  2391. if (CurrentSym[0] == '\0' ||
  2392. strncmp(Symbol->Name,CurrentSym,strlen(CurrentSym))) {
  2393. if (CurrentAddr != 0) {
  2394. ULONG64 Size = (Current->Base+i*ZOOM_BUCKET) - CurrentAddr;
  2395. if ( Size == 0 ) {
  2396. FPRINTF( stderr, "XXTF Size==0 - %s = %s\n", Symbol->Name, CurrentSym );
  2397. }
  2398. else {
  2399. if (!EnumSymbolsCallback(CurrentSym,CurrentAddr,(ULONG)Size,NULL)) {
  2400. break;
  2401. }
  2402. }
  2403. }
  2404. // Save the new info
  2405. CurrentAddr = Current->Base+i*ZOOM_BUCKET;
  2406. strcpy(CurrentSym,Symbol->Name);
  2407. }
  2408. }
  2409. }
  2410. // Cleanup for the last symbol
  2411. if (CurrentAddr != 0) {
  2412. ULONG64 Size = (Current->Base+i*ZOOM_BUCKET) - CurrentAddr;
  2413. (VOID) EnumSymbolsCallback(CurrentSym,CurrentAddr,(ULONG)Size,NULL);
  2414. }
  2415. return(TRUE);
  2416. } // TkEnumerateSymbols()
  2417. VOID
  2418. CreateZoomedModuleList(
  2419. IN PMODULE ZoomModule,
  2420. IN ULONG RoundDown
  2421. )
  2422. /*++
  2423. Routine Description:
  2424. Creates a module list from the functions in a given module
  2425. Arguments:
  2426. ZoomModule - Supplies the module whose zoomed module list is to be created
  2427. Return Value:
  2428. Pointer to the zoomed module list
  2429. NULL on error.
  2430. --*/
  2431. {
  2432. BOOL Success;
  2433. CallbackCurrent = ZoomModule;
  2434. if (RoundDown == 0) {
  2435. Success = SymEnumerateSymbols64( SymHandle,
  2436. ZoomModule->Base,
  2437. CreateZoomModuleCallback, NULL );
  2438. }
  2439. else {
  2440. Success = TkEnumerateSymbols( SymHandle,
  2441. ZoomModule,
  2442. CreateZoomModuleCallback );
  2443. }
  2444. if (!Success) {
  2445. FPRINTF(stderr,
  2446. "SymEnumerateSymbols64 failed module %s\n",
  2447. ZoomModule->module_Name);
  2448. }
  2449. return;
  2450. } // CreateZoomedModuleList()
  2451. VOID
  2452. OutputModuleList(
  2453. IN FILE *Out,
  2454. IN PMODULE ModuleList,
  2455. IN ULONG NumberModules
  2456. )
  2457. /*++
  2458. Routine Description:
  2459. Outputs the given module list
  2460. Arguments:
  2461. Out - Supplies the FILE * where the output should go.
  2462. ModuleList - Supplies the list of modules to output
  2463. NumberModules - Supplies the number of modules in the list
  2464. Return Value:
  2465. None.
  2466. --*/
  2467. {
  2468. CHAR HeaderString[128];
  2469. PRATE_DATA RateData;
  2470. PRATE_SUMMARY RateSummary;
  2471. PRATE_DATA SummaryData;
  2472. BOOLEAN Header;
  2473. ULONG i, ProfileSourceIndex;
  2474. PMODULE *ModuleArray;
  2475. PMODULE Current;
  2476. SYSTEM_PERFORMANCE_INFORMATION SystemInfoBegin;
  2477. SYSTEM_PERFORMANCE_INFORMATION SystemInfoEnd;
  2478. float Ratio;
  2479. //// Beginning of Function Assertions Section:
  2480. //
  2481. //
  2482. //
  2483. // It is not really a bug but we are printing only the first 32 characters of the module name.
  2484. // This assertion will remind us this.
  2485. //
  2486. assert( sizeof(Current->module_Name) >= 32 );
  2487. //
  2488. //
  2489. //// End of Function Assertions Section
  2490. RateSummary = malloc(SourceMaximum * sizeof (RATE_SUMMARY));
  2491. if (RateSummary == NULL) {
  2492. FPRINTF(stderr, "KERNRATE: Buffer allocation failed while doing output of Module list\n");
  2493. exit(1);
  2494. }
  2495. SummaryData = malloc(SourceMaximum * sizeof (RATE_DATA));
  2496. if (SummaryData == NULL) {
  2497. FPRINTF(stderr, "KERNRATE: Buffer allocation failed while doing output of Module list\n");
  2498. free(RateSummary);
  2499. exit(1);
  2500. }
  2501. ZeroMemory(SummaryData, SourceMaximum * sizeof (RATE_SUMMARY));
  2502. for (ProfileSourceIndex=0; ProfileSourceIndex < SourceMaximum; ProfileSourceIndex++) {
  2503. SummaryData[ProfileSourceIndex].Rate = 0;
  2504. if (Source[ProfileSourceIndex].Interval != 0) {
  2505. //
  2506. // Walk through the module list and compute the summary
  2507. // and collect the interesting per-module data.
  2508. //
  2509. RateSummary[ProfileSourceIndex].Modules = malloc(NumberModules * sizeof(PMODULE));
  2510. if (RateSummary[ProfileSourceIndex].Modules == NULL) {
  2511. FPRINTF(stderr, "KERNRATE: Buffer allocation failed while doing output of Module list\n");
  2512. exit(1);
  2513. }
  2514. RateSummary[ProfileSourceIndex].ModuleCount = 0;
  2515. RateSummary[ProfileSourceIndex].TotalCount = 0;
  2516. ModuleArray = RateSummary[ProfileSourceIndex].Modules;
  2517. Current = ModuleList;
  2518. while (Current != NULL) {
  2519. RateData = &Current->Rate[ProfileSourceIndex];
  2520. if (RateData->TotalCount > 0) {
  2521. RateSummary[ProfileSourceIndex].TotalCount += RateData->TotalCount;
  2522. //
  2523. // Insert it in sorted position in the array.
  2524. //
  2525. ModuleArray[RateSummary[ProfileSourceIndex].ModuleCount] = Current;
  2526. RateSummary[ProfileSourceIndex].ModuleCount++;
  2527. if (RateSummary[ProfileSourceIndex].ModuleCount > NumberModules) {
  2528. DbgPrint("error, ModuleCount %d > NumberModules %d for Source %s\n",
  2529. RateSummary[ProfileSourceIndex].ModuleCount,
  2530. NumberModules,
  2531. Source[ProfileSourceIndex].Name);
  2532. DbgBreakPoint();
  2533. }
  2534. for (i=0; i<RateSummary[ProfileSourceIndex].ModuleCount; i++) {
  2535. if (RateData->TotalCount > ModuleArray[i]->Rate[ProfileSourceIndex].TotalCount) {
  2536. //
  2537. // insert here
  2538. //
  2539. MoveMemory(&ModuleArray[i+1],
  2540. &ModuleArray[i],
  2541. sizeof(PMODULE)*(RateSummary[ProfileSourceIndex].ModuleCount-i-1));
  2542. ModuleArray[i] = Current;
  2543. break;
  2544. }
  2545. }
  2546. }
  2547. Current = Current->Next;
  2548. }
  2549. if (RateSummary[ProfileSourceIndex].TotalCount > (ULONGLONG)0) {
  2550. //
  2551. // Output the result
  2552. //
  2553. PSOURCE s;
  2554. s = &Source[ProfileSourceIndex];
  2555. FPRINTF(Out, "\n%s %I64u hits, %ld events per hit --------\n",
  2556. s->Name,
  2557. RateSummary[ProfileSourceIndex].TotalCount,
  2558. s->Interval
  2559. );
  2560. FPRINTF(Out," Module Hits msec %%Total Events/Sec\n");
  2561. for (i=0; i < RateSummary[ProfileSourceIndex].ModuleCount; i++) {
  2562. Current = ModuleArray[i];
  2563. FPRINTF(Out, "%-32s",Current->module_Name); // Note TF 09/97: the first only 32 characters are printed.
  2564. OutputLine(Out,
  2565. ProfileSourceIndex,
  2566. Current,
  2567. &RateSummary[ProfileSourceIndex]);
  2568. SummaryData[ProfileSourceIndex].Rate += Current->Rate[ProfileSourceIndex].Rate;
  2569. }
  2570. }
  2571. }
  2572. }
  2573. //
  2574. // Output interesting data for the summary.
  2575. //
  2576. sprintf(HeaderString, "\n-------------- INTERESTING SUMMARY DATA ----------------------\n");
  2577. OutputInterestingData(Out, SummaryData, HeaderString);
  2578. //
  2579. // Output the results ordered by module
  2580. //
  2581. Current = ModuleList;
  2582. while (Current != NULL) {
  2583. Header = FALSE;
  2584. for (ProfileSourceIndex = 0; ProfileSourceIndex < SourceMaximum; ProfileSourceIndex++) {
  2585. if ((Source[ProfileSourceIndex].Interval != 0) &&
  2586. (Current->Rate[ProfileSourceIndex].TotalCount > 0)) {
  2587. if (!Header) {
  2588. FPRINTF(Out,"\nMODULE %s --------\n",Current->module_Name);
  2589. FPRINTF(Out," %-*s Hits msec %%Total Events/Sec\n", DescriptionMaxLen, "Source");
  2590. Header = TRUE;
  2591. }
  2592. FPRINTF(Out, "%-*s", DescriptionMaxLen, Source[ProfileSourceIndex].Name);
  2593. OutputLine(Out,
  2594. ProfileSourceIndex,
  2595. Current,
  2596. &RateSummary[ProfileSourceIndex]);
  2597. }
  2598. }
  2599. //
  2600. // Output interesting data for the module.
  2601. //
  2602. sprintf(HeaderString, "\n-------------- INTERESTING MODULE DATA FOR %s---------------------- \n",Current->module_Name);
  2603. OutputInterestingData(Out, &Current->Rate[0], HeaderString);
  2604. Current = Current->Next;
  2605. }
  2606. return;
  2607. } // OutputModuleList()
  2608. VOID
  2609. OutputLine(
  2610. IN FILE *Out,
  2611. IN ULONG ProfileSourceIndex,
  2612. IN PMODULE Module,
  2613. IN PRATE_SUMMARY RateSummary
  2614. )
  2615. /*++
  2616. Routine Description:
  2617. Outputs a line corresponding to the particular module/source
  2618. Arguments:
  2619. Out - Supplies the file pointer to output to.
  2620. ProfileSource - Supplies the source to use
  2621. Module - Supplies the module to be output
  2622. RateSummary - Supplies the rate summary for this source
  2623. Return Value:
  2624. None.
  2625. --*/
  2626. {
  2627. ULONG Msec;
  2628. ULONGLONG Events;
  2629. Msec = (ULONG)(Module->Rate[ProfileSourceIndex].TotalTime/10000);
  2630. Events = Module->Rate[ProfileSourceIndex].TotalCount * Source[ProfileSourceIndex].Interval * 1000;
  2631. FPRINTF(Out,
  2632. " %10Ld %10d %2d %% ",
  2633. (ULONG) Module->Rate[ProfileSourceIndex].TotalCount,
  2634. (ULONG) Msec,
  2635. (ULONG)(100*Module->Rate[ProfileSourceIndex].TotalCount/
  2636. RateSummary->TotalCount));
  2637. if (Msec > 0) {
  2638. Module->Rate[ProfileSourceIndex].Rate = (ULONGLONG)Events/Msec;
  2639. FPRINTF(Out,"%10Ld\n",Module->Rate[ProfileSourceIndex].Rate);
  2640. } else {
  2641. Module->Rate[ProfileSourceIndex].Rate = 0;
  2642. FPRINTF(Out,"---\n");
  2643. }
  2644. }
  2645. VOID
  2646. OutputInterestingData(
  2647. IN FILE *Out,
  2648. IN RATE_DATA Data[],
  2649. IN PCHAR Header
  2650. )
  2651. /*++
  2652. Routine Description:
  2653. Computes interesting numbers and outputs them.
  2654. Arguments:
  2655. Out - Supplies the file pointer to output to.
  2656. Data - Supplies an array of RATE_DATA. The Rate field is the only interesting part.
  2657. Header - Supplies header to be printed.
  2658. Return Value:
  2659. None.
  2660. --*/
  2661. {
  2662. ULONGLONG Temp1,Temp2;
  2663. LONGLONG Temp3;
  2664. float Ratio;
  2665. BOOLEAN DidHeader = FALSE;
  2666. //
  2667. // Note that we have to do a lot of funky (float)(LONGLONG) casts in order
  2668. // to prevent the weenie x86 compiler from choking.
  2669. //
  2670. //
  2671. // Compute cycles/instruction and instruction mix data.
  2672. //
  2673. if ((Data[ProfileTotalIssues].Rate != 0) &&
  2674. (Data[ProfileTotalIssues].TotalCount > 10)) {
  2675. if (Data[ProfileTotalCycles].Rate != 0) {
  2676. Ratio = (float)(LONGLONG)(Data[ProfileTotalCycles].Rate)/
  2677. (float)(LONGLONG)(Data[ProfileTotalIssues].Rate);
  2678. if (!DidHeader) {
  2679. FPRINTF(Out, Header);
  2680. DidHeader = TRUE;
  2681. }
  2682. FPRINTF(Out, "Cycles per instruction\t\t%6.2f\n", Ratio);
  2683. }
  2684. Ratio = (float)(LONGLONG)(Data[ProfileLoadInstructions].Rate)/
  2685. (float)(LONGLONG)(Data[ProfileTotalIssues].Rate);
  2686. if (Ratio >= 0.01) {
  2687. if (!DidHeader) {
  2688. FPRINTF(Out, Header);
  2689. DidHeader = TRUE;
  2690. }
  2691. FPRINTF(Out, "Load instruction percentage\t%6.2f %%\n",Ratio*100);
  2692. }
  2693. Ratio = (float)(LONGLONG)(Data[ProfileStoreInstructions].Rate)/
  2694. (float)(LONGLONG)(Data[ProfileTotalIssues].Rate);
  2695. if (Ratio >= 0.01) {
  2696. if (!DidHeader) {
  2697. FPRINTF(Out, Header);
  2698. DidHeader = TRUE;
  2699. }
  2700. FPRINTF(Out, "Store instruction percentage\t%6.2f %%\n",Ratio*100);
  2701. }
  2702. Ratio = (float)(LONGLONG)(Data[ProfileBranchInstructions].Rate)/
  2703. (float)(LONGLONG)(Data[ProfileTotalIssues].Rate);
  2704. if (Ratio >= 0.01) {
  2705. if (!DidHeader) {
  2706. FPRINTF(Out, Header);
  2707. DidHeader = TRUE;
  2708. }
  2709. FPRINTF(Out, "Branch instruction percentage\t%6.2f %%\n",Ratio*100);
  2710. }
  2711. Ratio = (float)(LONGLONG)(Data[ProfileFpInstructions].Rate)/
  2712. (float)(LONGLONG)(Data[ProfileTotalIssues].Rate);
  2713. if (Ratio >= 0.01) {
  2714. if (!DidHeader) {
  2715. FPRINTF(Out, Header);
  2716. DidHeader = TRUE;
  2717. }
  2718. FPRINTF(Out, "FP instruction percentage\t%6.2f %%\n",Ratio*100);
  2719. }
  2720. Ratio = (float)(LONGLONG)(Data[ProfileIntegerInstructions].Rate)/
  2721. (float)(LONGLONG)(Data[ProfileTotalIssues].Rate);
  2722. if (Ratio >= 0.01) {
  2723. if (!DidHeader) {
  2724. FPRINTF(Out, Header);
  2725. DidHeader = TRUE;
  2726. }
  2727. FPRINTF(Out, "Integer instruction percentage\t%6.2f %%\n",Ratio*100);
  2728. }
  2729. //
  2730. // Compute icache hit rate
  2731. //
  2732. if (Data[ProfileIcacheMisses].Rate != 0) {
  2733. Temp3 = (LONGLONG)(Data[ProfileTotalIssues].Rate - Data[ProfileIcacheMisses].Rate);
  2734. Ratio = (float)Temp3/
  2735. (float)(LONGLONG)(Data[ProfileTotalIssues].Rate);
  2736. if (!DidHeader) {
  2737. FPRINTF(Out, Header);
  2738. DidHeader = TRUE;
  2739. }
  2740. FPRINTF(Out, "Icache hit rate\t\t\t%6.2f %%\n", Ratio*100);
  2741. }
  2742. }
  2743. //
  2744. // Compute dcache hit rate
  2745. //
  2746. Temp1 = Data[ProfileLoadInstructions].Rate + Data[ProfileStoreInstructions].Rate;
  2747. if ((Data[ProfileDcacheMisses].Rate != 0) &&
  2748. (Temp1 != 0) &&
  2749. (Data[ProfileDcacheMisses].TotalCount > 10)) {
  2750. Temp2 = Temp1 - Data[ProfileDcacheMisses].Rate;
  2751. Temp3 = (LONGLONG) Temp2;
  2752. Ratio = (float)Temp3/(float)(LONGLONG)Temp1;
  2753. if (!DidHeader) {
  2754. FPRINTF(Out, Header);
  2755. DidHeader = TRUE;
  2756. }
  2757. FPRINTF(Out, "Dcache hit rate\t\t\t%6.2f %%\n", Ratio*100);
  2758. }
  2759. //
  2760. // Compute branch prediction hit percentage
  2761. //
  2762. if ((Data[ProfileBranchInstructions].Rate != 0) &&
  2763. (Data[ProfileBranchMispredictions].Rate != 0) &&
  2764. (Data[ProfileBranchInstructions].TotalCount > 10)) {
  2765. Temp3 = (LONGLONG)(Data[ProfileBranchInstructions].Rate-Data[ProfileBranchMispredictions].Rate);
  2766. Ratio = (float)Temp3 /
  2767. (float)(LONGLONG)(Data[ProfileBranchInstructions].Rate);
  2768. if (!DidHeader) {
  2769. FPRINTF(Out, Header);
  2770. DidHeader = TRUE;
  2771. }
  2772. FPRINTF(Out, "Branch predict hit percentage\t%6.2f %%\n", Ratio*100);
  2773. }
  2774. } // OutputInterestingData()
  2775. /* BEGIN_IMS CreateNewModule
  2776. ******************************************************************************
  2777. ****
  2778. **** CreateNewModule ( )
  2779. ****
  2780. ******************************************************************************
  2781. *
  2782. * Function Description:
  2783. *
  2784. * This function allocates and initializes a module entry.
  2785. *
  2786. * Arguments:
  2787. *
  2788. * IN HANDLE ProcessHandle :
  2789. *
  2790. * IN PCHAR ModuleName :
  2791. *
  2792. * IN PCHAR ModuleFullName :
  2793. *
  2794. * IN ULONG ImageBase :
  2795. *
  2796. * IN ULONG ImageSize :
  2797. *
  2798. * Return Value:
  2799. *
  2800. * PMODULE
  2801. *
  2802. * Algorithm:
  2803. *
  2804. * ToBeSpecified
  2805. *
  2806. * Globals Referenced:
  2807. *
  2808. * ToBeSpecified
  2809. *
  2810. * Exception Conditions:
  2811. *
  2812. * ToBeSpecified
  2813. *
  2814. * In/Out Conditions:
  2815. *
  2816. * ToBeSpecified
  2817. *
  2818. * Notes:
  2819. *
  2820. * ToBeSpecified
  2821. *
  2822. * ToDo List:
  2823. *
  2824. * ToBeSpecified
  2825. *
  2826. * Modification History:
  2827. *
  2828. * 9/8/97 TF Initial version
  2829. *
  2830. ******************************************************************************
  2831. * END_IMS CreateNewModule */
  2832. PMODULE
  2833. CreateNewModule(
  2834. IN HANDLE ProcessHandle,
  2835. IN PCHAR ModuleName,
  2836. IN PCHAR ModuleFullName,
  2837. IN ULONG64 ImageBase,
  2838. IN ULONG ImageSize
  2839. )
  2840. {
  2841. PMODULE NewModule;
  2842. PMODULE ZoomModule;
  2843. PMODULE *ZoomPrevious;
  2844. NewModule = calloc(1, sizeof(MODULE)+sizeof(RATE_DATA)*SourceMaximum);
  2845. if (NewModule == NULL) {
  2846. FPRINTF(stderr,"Memory allocation of NewModule for %s failed\n",ModuleName);
  2847. exit(1);
  2848. }
  2849. NewModule->Zoom = FALSE;
  2850. SetModuleName( NewModule, ModuleName );
  2851. //
  2852. // Following WinDbg's rule: module names are filenames without their extension.
  2853. //
  2854. if (strchr(NewModule->module_Name, '.')) {
  2855. *strchr(NewModule->module_Name, '.') = '\0';
  2856. }
  2857. //
  2858. // See if this module is on the zoom list.
  2859. // If so we will use the MODULE that was allocated when
  2860. // the zoom list was created.
  2861. //
  2862. ZoomModule = ZoomList;
  2863. ZoomPrevious = &ZoomList;
  2864. while ( ZoomModule != NULL ) {
  2865. if ( _stricmp(ZoomModule->module_Name,NewModule->module_Name) == 0 ) {
  2866. //
  2867. // found a match
  2868. //
  2869. free(NewModule);
  2870. NewModule = ZoomModule;
  2871. *ZoomPrevious = ZoomModule->Next;
  2872. NewModule->Base = ImageBase;
  2873. NewModule->Length = ImageSize;
  2874. NewModule->module_FileName = _strdup( ModuleName );
  2875. if ( ModuleFullName ) {
  2876. NewModule->module_FullName = _strdup( ModuleFullName );
  2877. }
  2878. gCurrentModule = NewModule;
  2879. //
  2880. // Load symbols
  2881. //
  2882. // Note 15/09/97 TF: do not be confused here...
  2883. // In this routine, the ModuleName variable is a filename with its
  2884. // extension: File.exe or File.dll
  2885. //
  2886. // Note 30/09/97 TF: The current kernrate version does not change
  2887. // the default IMAGEHLP behaviour in terms of symbol file loading:
  2888. // It is synchronous ( and not deferred ) with the SymLoadModule
  2889. // call. Our registered callback will be called with the standard
  2890. // symbol file operations.
  2891. // If the kernrate behaviour changes, we will have to revisit this
  2892. // assumption.
  2893. //
  2894. // Also, I decided to keep temporarely the kernrate "_OLD_CODE"
  2895. // in case the registered callback does not work as it should.
  2896. // We are still in the learning curve, here -).
  2897. //
  2898. #if defined(_OLD_CODE)
  2899. //
  2900. //
  2901. //
  2902. if ( SymLoadModule(ProcessHandle ? ProcessHandle : (HANDLE)-1, // hProcess
  2903. NULL, // hFile [for Debugger]
  2904. ModuleName, // ImageName
  2905. NULL, // ModuleName
  2906. ImageBase, // BaseOfDll
  2907. ImageSize // SizeOfDll
  2908. )) {
  2909. FPRINTF(stderr,
  2910. "Symbols loaded %08lx %s\n",
  2911. ImageBase,
  2912. ModuleName);
  2913. } else {
  2914. FPRINTF(stderr,
  2915. "*** Could not load symbols %08lx %s\n",
  2916. ImageBase,
  2917. ModuleName);
  2918. }
  2919. #else // _NEW_CODE
  2920. (void)SymLoadModule64( ProcessHandle ? ProcessHandle : (HANDLE)-1, // hProcess
  2921. NULL, // hFile [for Debugger]
  2922. ModuleName, // ImageName
  2923. NULL, // ModuleName
  2924. ImageBase, // BaseOfDll
  2925. ImageSize // SizeOfDll
  2926. );
  2927. #endif // _NEW_CODE
  2928. gCurrentModule = (PMODULE)0;
  2929. break;
  2930. }
  2931. ZoomPrevious = &ZoomModule->Next;
  2932. ZoomModule = ZoomModule->Next;
  2933. }
  2934. NewModule->Process = ProcessHandle;
  2935. NewModule->Base = ImageBase; // Note TF: I know for zoomed it is a redone...
  2936. NewModule->Length = ImageSize; // Note TF: I know for zoomed it is a redone...
  2937. assert( ModuleName );
  2938. if ( NewModule->module_FileName == (PCHAR)0 ) {
  2939. NewModule->module_FileName = _strdup( ModuleName );
  2940. }
  2941. if ( ModuleFullName && NewModule->module_FullName == (PCHAR)0 ) {
  2942. NewModule->module_FullName = _strdup( ModuleFullName );
  2943. }
  2944. ZeroMemory(NewModule->Rate, sizeof(RATE_DATA) * SourceMaximum);
  2945. #ifdef _WIN64
  2946. #define VerboseModuleFormat "0x%016x 0x%16x "
  2947. #else // !_WIN64
  2948. #define VerboseModuleFormat "0x%08x 0x%08x "
  2949. #endif // !_WIN64
  2950. VerbosePrint(( VERBOSE_MODULES, VerboseModuleFormat " %s [%s]\n",
  2951. NewModule->Base,
  2952. NewModule->Base + (ULONG64)NewModule->Length,
  2953. NewModule->module_Name,
  2954. ModuleFullName( NewModule )
  2955. ));
  2956. #undef VerboseModuleFormat
  2957. return(NewModule);
  2958. } // CreateNewModule()