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.

1029 lines
39 KiB

  1. #include <nt.h>
  2. #include <ntrtl.h>
  3. #include <nturtl.h>
  4. #include <windows.h>
  5. #include <imagehlp.h>
  6. #include <psapi.h>
  7. #include <stdlib.h>
  8. #include <stdio.h>
  9. #define MAX_SYMNAME_SIZE 1024
  10. CHAR symBuffer[sizeof(IMAGEHLP_SYMBOL)+MAX_SYMNAME_SIZE];
  11. PIMAGEHLP_SYMBOL ThisSymbol = (PIMAGEHLP_SYMBOL) symBuffer;
  12. CHAR LastSymBuffer[sizeof(IMAGEHLP_SYMBOL)+MAX_SYMNAME_SIZE];
  13. PIMAGEHLP_SYMBOL LastSymbol = (PIMAGEHLP_SYMBOL) LastSymBuffer;
  14. CHAR BadSymBuffer[sizeof(IMAGEHLP_SYMBOL)+MAX_SYMNAME_SIZE];
  15. PIMAGEHLP_SYMBOL BadSymbol = (PIMAGEHLP_SYMBOL)BadSymBuffer;
  16. BOOL UseLastSymbol;
  17. typedef struct _PROFILE_BLOCK {
  18. HANDLE Handle;
  19. HANDLE SecondaryHandle;
  20. PVOID ImageBase;
  21. BOOL SymbolsLoaded;
  22. PULONG CodeStart;
  23. ULONG CodeLength;
  24. PULONG Buffer;
  25. PULONG SecondaryBuffer;
  26. ULONG BufferSize;
  27. ULONG TextNumber;
  28. ULONG BucketSize;
  29. PUNICODE_STRING ImageName;
  30. char *ImageFileName;
  31. } PROFILE_BLOCK;
  32. ULONG ProfilePageSize;
  33. #define MAX_BYTE_PER_LINE 72
  34. #define MAX_PROFILE_COUNT 100
  35. #define SYM_HANDLE ((HANDLE)UlongToPtr(0xffffffff))
  36. PROFILE_BLOCK ProfileObject[MAX_PROFILE_COUNT+1];
  37. ULONG NumberOfProfileObjects = 0;
  38. ULONG ProfileInterval = 4882;
  39. #define BUCKETSIZE 4
  40. int PowerOfBytesCoveredPerBucket = 2;
  41. CHAR SymbolSearchPathBuf[4096];
  42. LPSTR SymbolSearchPath = SymbolSearchPathBuf;
  43. BOOLEAN ShowAllHits = FALSE;
  44. BOOLEAN fKernel = FALSE;
  45. PCHAR OutputFile = "profile.out";
  46. KPROFILE_SOURCE ProfileSource = ProfileTime;
  47. KPROFILE_SOURCE SecondaryProfileSource = ProfileTime;
  48. BOOLEAN UseSecondaryProfile = FALSE;
  49. //
  50. // define the mappings between arguments and KPROFILE_SOURCE types
  51. //
  52. typedef struct _PROFILE_SOURCE_MAPPING {
  53. PCHAR Name;
  54. KPROFILE_SOURCE Source;
  55. } PROFILE_SOURCE_MAPPING, *PPROFILE_SOURCE_MAPPING;
  56. PROFILE_SOURCE_MAPPING ProfileSourceMapping[] = {
  57. {NULL,0}
  58. };
  59. VOID
  60. PsParseCommandLine(
  61. VOID
  62. );
  63. VOID
  64. PsWriteProfileLine(
  65. IN HANDLE ProfileHandle,
  66. IN PSZ Line,
  67. IN int nbytes
  68. )
  69. {
  70. IO_STATUS_BLOCK IoStatusBlock;
  71. NtWriteFile(
  72. ProfileHandle,
  73. NULL,
  74. NULL,
  75. NULL,
  76. &IoStatusBlock,
  77. Line,
  78. (ULONG)nbytes,
  79. NULL,
  80. NULL
  81. );
  82. }
  83. NTSTATUS
  84. PsInitializeAndStartProfile(
  85. VOID
  86. )
  87. {
  88. HANDLE CurrentProcessHandle;
  89. SIZE_T BufferSize;
  90. PVOID ImageBase;
  91. PULONG CodeStart;
  92. ULONG CodeLength;
  93. PULONG Buffer;
  94. PPEB Peb;
  95. PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
  96. PUNICODE_STRING ImageName;
  97. PLIST_ENTRY Next;
  98. SYSTEM_BASIC_INFORMATION SystemInfo;
  99. NTSTATUS status;
  100. ULONG i;
  101. CHAR Bogus[256];
  102. CHAR *ImageFileName;
  103. SIZE_T WsMin, WsMax;
  104. ULONG ModuleNumber;
  105. CHAR ModuleInfoBuffer[64000];
  106. ULONG ReturnedLength;
  107. PRTL_PROCESS_MODULES Modules;
  108. PRTL_PROCESS_MODULE_INFORMATION Module;
  109. BOOLEAN PreviousProfilePrivState;
  110. BOOLEAN PreviousQuotaPrivState;
  111. BOOLEAN Done = FALSE;
  112. BOOLEAN DuplicateObject = FALSE;
  113. //
  114. // Get the page size.
  115. //
  116. status = NtQuerySystemInformation (SystemBasicInformation,
  117. &SystemInfo,
  118. sizeof(SystemInfo),
  119. NULL);
  120. if (!NT_SUCCESS(status)) {
  121. return status;
  122. }
  123. //
  124. // Load kernel modules
  125. //
  126. if (fKernel) {
  127. status = NtQuerySystemInformation (
  128. SystemModuleInformation,
  129. ModuleInfoBuffer,
  130. sizeof( ModuleInfoBuffer ),
  131. &ReturnedLength);
  132. if (!NT_SUCCESS(status)) {
  133. DbgPrint("query system info failed status - %lx\n",status);
  134. fKernel = FALSE;
  135. } else {
  136. Modules = (PRTL_PROCESS_MODULES)ModuleInfoBuffer;
  137. Module = &Modules->Modules[ 0 ];
  138. ModuleNumber = 0;
  139. status = RtlAdjustPrivilege(
  140. SE_SYSTEM_PROFILE_PRIVILEGE,
  141. TRUE, //Enable
  142. FALSE, //not impersonating
  143. &PreviousProfilePrivState
  144. );
  145. if (!NT_SUCCESS(status) || status == STATUS_NOT_ALL_ASSIGNED) {
  146. DbgPrint("Enable system profile privilege failed - status 0x%lx\n",
  147. status);
  148. }
  149. status = RtlAdjustPrivilege(
  150. SE_INCREASE_QUOTA_PRIVILEGE,
  151. TRUE, //Enable
  152. FALSE, //not impersonating
  153. &PreviousQuotaPrivState
  154. );
  155. if (!NT_SUCCESS(status) || status == STATUS_NOT_ALL_ASSIGNED) {
  156. DbgPrint("Unable to increase quota privilege (status=0x%lx)\n",
  157. status);
  158. }
  159. }
  160. }
  161. ProfilePageSize = SystemInfo.PageSize;
  162. //
  163. // Locate all the executables in the address and create a
  164. // seperate profile object for each one.
  165. //
  166. CurrentProcessHandle = NtCurrentProcess();
  167. Peb = NtCurrentPeb();
  168. Next = Peb->Ldr->InMemoryOrderModuleList.Flink;
  169. while (!Done) {
  170. if ( Next != &Peb->Ldr->InMemoryOrderModuleList) {
  171. LdrDataTableEntry = (PLDR_DATA_TABLE_ENTRY) (CONTAINING_RECORD(
  172. Next,
  173. LDR_DATA_TABLE_ENTRY,
  174. InMemoryOrderLinks
  175. ));
  176. Next = Next->Flink;
  177. ImageBase = LdrDataTableEntry->DllBase;
  178. ImageName = &LdrDataTableEntry->BaseDllName;
  179. CodeLength = LdrDataTableEntry->SizeOfImage;
  180. CodeStart = (PULONG)ImageBase;
  181. ImageFileName = HeapAlloc(GetProcessHeap(), 0, 256);
  182. if (!ImageFileName) {
  183. status = STATUS_NO_MEMORY;
  184. return status;
  185. }
  186. status = RtlUnicodeToOemN( ImageFileName,
  187. 256,
  188. &i,
  189. ImageName->Buffer,
  190. ImageName->Length
  191. );
  192. ImageFileName[i] = 0;
  193. if (status != STATUS_SUCCESS) {
  194. HeapFree(GetProcessHeap(), 0, ImageFileName);
  195. continue;
  196. }
  197. } else
  198. if (fKernel && (ModuleNumber < Modules->NumberOfModules)) {
  199. ULONG cNameMBLength = lstrlen(&Module->FullPathName[Module->OffsetToFileName]) + 1;
  200. ULONG cNameUCLength = cNameMBLength * sizeof(WCHAR);
  201. ULONG cNameSize = cNameUCLength + sizeof(UNICODE_STRING);
  202. ImageFileName = HeapAlloc(GetProcessHeap(), 0, cNameMBLength);
  203. if (!ImageFileName) {
  204. status = STATUS_NO_MEMORY;
  205. return status;
  206. }
  207. lstrcpy(ImageFileName, &Module->FullPathName[Module->OffsetToFileName]);
  208. ImageBase = Module->ImageBase;
  209. CodeLength = Module->ImageSize;
  210. CodeStart = (PULONG)ImageBase;
  211. ImageName = HeapAlloc(GetProcessHeap(), 0, cNameSize);
  212. if (!ImageName) {
  213. status = STATUS_NO_MEMORY;
  214. return status;
  215. }
  216. ImageName->Buffer = (WCHAR *)((PBYTE)ImageName + sizeof(UNICODE_STRING));
  217. RtlMultiByteToUnicodeN(ImageName->Buffer, cNameUCLength, &i,
  218. &Module->FullPathName[Module->OffsetToFileName],
  219. cNameMBLength);
  220. ImageName->Length = (USHORT)i;
  221. Module++;
  222. ModuleNumber++;
  223. } else {
  224. Done = TRUE;
  225. break;
  226. }
  227. DuplicateObject = FALSE;
  228. for (i = 0; i < NumberOfProfileObjects ; i++ ) {
  229. if (ImageBase == ProfileObject[i].ImageBase)
  230. DuplicateObject = TRUE;
  231. }
  232. if (DuplicateObject) {
  233. continue;
  234. }
  235. ProfileObject[NumberOfProfileObjects].ImageBase = ImageBase;
  236. ProfileObject[NumberOfProfileObjects].ImageName = ImageName;
  237. ProfileObject[NumberOfProfileObjects].ImageFileName = ImageFileName;
  238. ProfileObject[NumberOfProfileObjects].CodeLength = CodeLength;
  239. ProfileObject[NumberOfProfileObjects].CodeStart = CodeStart;
  240. ProfileObject[NumberOfProfileObjects].TextNumber = 1;
  241. //
  242. // Analyze the size of the code and create a reasonably sized
  243. // profile object.
  244. //
  245. BufferSize = ((CodeLength * BUCKETSIZE) >> PowerOfBytesCoveredPerBucket) + 4;
  246. Buffer = NULL;
  247. status = NtAllocateVirtualMemory (CurrentProcessHandle,
  248. (PVOID *)&Buffer,
  249. 0,
  250. &BufferSize,
  251. MEM_RESERVE | MEM_COMMIT,
  252. PAGE_READWRITE);
  253. if (!NT_SUCCESS(status)) {
  254. DbgPrint ("RtlInitializeProfile : alloc VM failed %lx\n",status);
  255. return status;
  256. }
  257. ProfileObject[NumberOfProfileObjects].Buffer = Buffer;
  258. ProfileObject[NumberOfProfileObjects].BufferSize = (ULONG)BufferSize;
  259. ProfileObject[NumberOfProfileObjects].BucketSize = PowerOfBytesCoveredPerBucket;
  260. status = NtCreateProfile (
  261. &ProfileObject[NumberOfProfileObjects].Handle,
  262. CurrentProcessHandle,
  263. ProfileObject[NumberOfProfileObjects].CodeStart,
  264. ProfileObject[NumberOfProfileObjects].CodeLength,
  265. ProfileObject[NumberOfProfileObjects].BucketSize,
  266. ProfileObject[NumberOfProfileObjects].Buffer ,
  267. ProfileObject[NumberOfProfileObjects].BufferSize,
  268. ProfileSource,
  269. (KAFFINITY)-1);
  270. if (status != STATUS_SUCCESS) {
  271. DbgPrint("create profile %wZ failed - status %lx\n",
  272. ProfileObject[NumberOfProfileObjects].ImageName,status);
  273. return status;
  274. }
  275. if (UseSecondaryProfile) {
  276. Buffer = NULL;
  277. status = NtAllocateVirtualMemory (CurrentProcessHandle,
  278. (PVOID *)&Buffer,
  279. 0,
  280. &BufferSize,
  281. MEM_RESERVE | MEM_COMMIT,
  282. PAGE_READWRITE);
  283. if (!NT_SUCCESS(status)) {
  284. DbgPrint ("RtlInitializeProfile : secondary alloc VM failed %lx\n",status);
  285. return status;
  286. }
  287. ProfileObject[NumberOfProfileObjects].SecondaryBuffer = Buffer;
  288. status = NtCreateProfile (
  289. &ProfileObject[NumberOfProfileObjects].SecondaryHandle,
  290. CurrentProcessHandle,
  291. ProfileObject[NumberOfProfileObjects].CodeStart,
  292. ProfileObject[NumberOfProfileObjects].CodeLength,
  293. ProfileObject[NumberOfProfileObjects].BucketSize,
  294. ProfileObject[NumberOfProfileObjects].SecondaryBuffer,
  295. ProfileObject[NumberOfProfileObjects].BufferSize,
  296. SecondaryProfileSource,
  297. (KAFFINITY)-1);
  298. if (status != STATUS_SUCCESS) {
  299. DbgPrint("create profile %wZ failed - status %lx\n",
  300. ProfileObject[NumberOfProfileObjects].ImageName,status);
  301. return status;
  302. }
  303. }
  304. NumberOfProfileObjects++;
  305. if (NumberOfProfileObjects == MAX_PROFILE_COUNT) {
  306. break;
  307. }
  308. }
  309. NtSetIntervalProfile(ProfileInterval,ProfileSource);
  310. if (UseSecondaryProfile) {
  311. NtSetIntervalProfile(ProfileInterval,SecondaryProfileSource);
  312. }
  313. for (i = 0; i < NumberOfProfileObjects; i++) {
  314. status = NtStartProfile (ProfileObject[i].Handle);
  315. if (status == STATUS_WORKING_SET_QUOTA) {
  316. //
  317. // Increase the working set to lock down a bigger buffer.
  318. //
  319. GetProcessWorkingSetSize(CurrentProcessHandle,&WsMin,&WsMax);
  320. WsMax += 10*ProfilePageSize + ProfileObject[i].BufferSize;
  321. WsMin += 10*ProfilePageSize + ProfileObject[i].BufferSize;
  322. SetProcessWorkingSetSize(CurrentProcessHandle,WsMin,WsMax);
  323. status = NtStartProfile (ProfileObject[i].Handle);
  324. }
  325. if (status != STATUS_SUCCESS) {
  326. DbgPrint("start profile %wZ failed - status %lx\n",
  327. ProfileObject[i].ImageName, status);
  328. return status;
  329. }
  330. if (UseSecondaryProfile) {
  331. status = NtStartProfile (ProfileObject[i].SecondaryHandle);
  332. if (status == STATUS_WORKING_SET_QUOTA) {
  333. //
  334. // Increase the working set to lock down a bigger buffer.
  335. //
  336. GetProcessWorkingSetSize(CurrentProcessHandle,&WsMin,&WsMax);
  337. WsMax += 10*ProfilePageSize + ProfileObject[i].BufferSize;
  338. WsMin += 10*ProfilePageSize + ProfileObject[i].BufferSize;
  339. SetProcessWorkingSetSize(CurrentProcessHandle,WsMin,WsMax);
  340. status = NtStartProfile (ProfileObject[i].SecondaryHandle);
  341. }
  342. if (status != STATUS_SUCCESS) {
  343. DbgPrint("start secondary profile %wZ failed - status %lx\n",
  344. ProfileObject[i].ImageName, status);
  345. return status;
  346. }
  347. }
  348. }
  349. return status;
  350. }
  351. unsigned long
  352. Percent(
  353. unsigned long arg1,
  354. unsigned long arg2,
  355. unsigned long * Low
  356. )
  357. {
  358. unsigned long iarg1 = arg1;
  359. unsigned __int64 iarg2 = arg2 * 100000;
  360. unsigned long diff, High;
  361. diff = (unsigned long) (iarg2 / iarg1);
  362. while (diff > 100000) {
  363. diff /= 100000;
  364. }
  365. High = diff / 1000;
  366. *Low = diff % 1000;
  367. return(High);
  368. }
  369. NTSTATUS
  370. PsStopAndAnalyzeProfile(
  371. VOID
  372. )
  373. {
  374. NTSTATUS status;
  375. ULONG CountAtSymbol;
  376. ULONG SecondaryCountAtSymbol;
  377. NTSTATUS Status;
  378. ULONG_PTR Va;
  379. HANDLE ProfileHandle;
  380. CHAR Line[512];
  381. ULONG i, n, High, Low;
  382. PULONG Buffer, BufferEnd, Counter, InitialCounter;
  383. PULONG SecondaryBuffer;
  384. PULONG SecondaryInitialCounter;
  385. ULONG TotalCounts;
  386. ULONG ByteCount;
  387. IMAGEHLP_MODULE ModuleInfo;
  388. SIZE_T dwDisplacement;
  389. ModuleInfo.SizeOfStruct = sizeof(ModuleInfo);
  390. __try {
  391. // If there's a problem faulting in the symbol handler, just return.
  392. //
  393. // initialize the symbol handler
  394. //
  395. ThisSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
  396. ThisSymbol->MaxNameLength = MAX_SYMNAME_SIZE;
  397. LastSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
  398. LastSymbol->MaxNameLength = MAX_SYMNAME_SIZE;
  399. SymSetOptions( SYMOPT_UNDNAME | SYMOPT_CASE_INSENSITIVE | SYMOPT_OMAP_FIND_NEAREST);
  400. SymInitialize( SYM_HANDLE, NULL, FALSE );
  401. SymGetSearchPath( SYM_HANDLE, SymbolSearchPathBuf, sizeof(SymbolSearchPathBuf) );
  402. ZeroMemory( BadSymBuffer, sizeof(BadSymBuffer) );
  403. BadSymbol->Name[0] = (BYTE)lstrlen("No Symbol Found");
  404. lstrcpy( &BadSymbol->Name[1], "No Symbol Found" );
  405. BadSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
  406. BadSymbol->MaxNameLength = MAX_SYMNAME_SIZE;
  407. ProfileHandle = CreateFile(
  408. OutputFile,
  409. GENERIC_READ | GENERIC_WRITE,
  410. FILE_SHARE_READ | FILE_SHARE_WRITE,
  411. NULL,
  412. CREATE_ALWAYS,
  413. FILE_ATTRIBUTE_NORMAL,
  414. NULL
  415. );
  416. if ( ProfileHandle == INVALID_HANDLE_VALUE ) {
  417. return STATUS_UNSUCCESSFUL;
  418. }
  419. for (i = 0; i < NumberOfProfileObjects; i++) {
  420. Status = NtStopProfile (ProfileObject[i].Handle);
  421. }
  422. if (MAX_PROFILE_COUNT == NumberOfProfileObjects) {
  423. n = sprintf(Line,"Overflowed the maximum number of "
  424. "modules: %d\n",
  425. MAX_PROFILE_COUNT
  426. );
  427. PsWriteProfileLine(ProfileHandle,Line,n);
  428. }
  429. //
  430. // The new profiler
  431. //
  432. for (i = 0; i < NumberOfProfileObjects; i++) {
  433. UseLastSymbol = FALSE;
  434. CountAtSymbol = 0;
  435. SecondaryCountAtSymbol = 0;
  436. //
  437. // Sum the total number of cells written.
  438. //
  439. BufferEnd = ProfileObject[i].Buffer + (
  440. ProfileObject[i].BufferSize / sizeof(ULONG));
  441. Buffer = ProfileObject[i].Buffer;
  442. Counter = BufferEnd;
  443. if (UseSecondaryProfile) {
  444. SecondaryBuffer = ProfileObject[i].SecondaryBuffer;
  445. }
  446. TotalCounts = 0;
  447. while (Counter > Buffer) {
  448. Counter -= 1;
  449. TotalCounts += *Counter;
  450. }
  451. if (!TotalCounts) {
  452. // Don't bother wasting time loading symbols
  453. continue;
  454. }
  455. if (SymLoadModule( SYM_HANDLE, NULL, ProfileObject[i].ImageFileName, NULL,
  456. (DWORD_PTR)ProfileObject[i].ImageBase, 0)
  457. && SymGetModuleInfo(SYM_HANDLE, (DWORD_PTR)ProfileObject[i].ImageBase, &ModuleInfo)
  458. && (ModuleInfo.SymType != SymNone)
  459. )
  460. {
  461. ProfileObject[i].SymbolsLoaded = TRUE;
  462. } else {
  463. ProfileObject[i].SymbolsLoaded = FALSE;
  464. }
  465. n= sprintf(Line,"%d,%wZ,Total%s\n",
  466. TotalCounts,
  467. ProfileObject[i].ImageName,
  468. (ProfileObject[i].SymbolsLoaded) ? "" : " (NO SYMBOLS)"
  469. );
  470. PsWriteProfileLine(ProfileHandle,Line,n);
  471. if (ProfileObject[i].SymbolsLoaded) {
  472. InitialCounter = Buffer;
  473. if (UseSecondaryProfile) {
  474. SecondaryInitialCounter = SecondaryBuffer;
  475. }
  476. for ( Counter = Buffer; Counter < BufferEnd; Counter += 1 ) {
  477. if ( *Counter ) {
  478. //
  479. // Now we have an an address relative to the buffer
  480. // base.
  481. //
  482. Va = ((PUCHAR)Counter - (PUCHAR)Buffer);
  483. Va = Va * ( 1 << (ProfileObject[i].BucketSize - 2));
  484. //
  485. // Add in the image base and the base of the
  486. // code to get the Va in the image
  487. //
  488. Va = Va + (ULONG_PTR)ProfileObject[i].CodeStart;
  489. if (SymGetSymFromAddr( SYM_HANDLE, Va, &dwDisplacement, ThisSymbol )) {
  490. if ( UseLastSymbol && LastSymbol->Address == ThisSymbol->Address ) {
  491. CountAtSymbol += *Counter;
  492. if (UseSecondaryProfile) {
  493. SecondaryCountAtSymbol += *(SecondaryBuffer + (Counter-Buffer));
  494. }
  495. } else {
  496. if ( UseLastSymbol && LastSymbol->Address ) {
  497. if ( CountAtSymbol || SecondaryCountAtSymbol) {
  498. if (!UseSecondaryProfile) {
  499. n= sprintf(Line,"%d,%wZ,%s (%08lx)\n",
  500. CountAtSymbol,
  501. ProfileObject[i].ImageName,
  502. LastSymbol->Name,
  503. LastSymbol->Address
  504. );
  505. } else {
  506. if (SecondaryCountAtSymbol != 0) {
  507. High = Percent(CountAtSymbol, SecondaryCountAtSymbol, &Low);
  508. n = sprintf(Line,"%d,%d,%2.2d.%3.3d,%wZ,%s (%08lx)\n",
  509. CountAtSymbol,
  510. SecondaryCountAtSymbol,
  511. High, Low,
  512. ProfileObject[i].ImageName,
  513. LastSymbol->Name,
  514. LastSymbol->Address
  515. );
  516. } else {
  517. n = sprintf(Line,"%d,%d, -- ,%wZ,%s (%08lx)\n",
  518. CountAtSymbol,
  519. SecondaryCountAtSymbol,
  520. ProfileObject[i].ImageName,
  521. LastSymbol->Name,
  522. LastSymbol->Address
  523. );
  524. }
  525. }
  526. PsWriteProfileLine(ProfileHandle,Line,n);
  527. if (ShowAllHits) {
  528. while (InitialCounter < Counter) {
  529. if (*InitialCounter) {
  530. Va = ((PUCHAR)InitialCounter - (PUCHAR)Buffer);
  531. Va = Va * (1 << (ProfileObject[i].BucketSize - 2));
  532. Va = Va + (ULONG_PTR)ProfileObject[i].CodeStart;
  533. if (!UseSecondaryProfile) {
  534. n = sprintf(Line, "\t%p:%d\n",
  535. Va,
  536. *InitialCounter);
  537. } else {
  538. if (*SecondaryInitialCounter != 0) {
  539. High = Percent(*InitialCounter, *SecondaryInitialCounter, &Low);
  540. n = sprintf(Line, "\t%p:%d, %d, %2.2d.%3.3d\n",
  541. Va,
  542. *InitialCounter,
  543. *SecondaryInitialCounter,
  544. High, Low);
  545. } else {
  546. n = sprintf(Line, "\t%p:%d, %d, --\n",
  547. Va,
  548. *InitialCounter,
  549. *SecondaryInitialCounter);
  550. }
  551. }
  552. PsWriteProfileLine(ProfileHandle, Line, n);
  553. }
  554. ++InitialCounter;
  555. ++SecondaryInitialCounter;
  556. }
  557. }
  558. }
  559. }
  560. InitialCounter = Counter;
  561. CountAtSymbol = *Counter;
  562. if (UseSecondaryProfile) {
  563. SecondaryInitialCounter = SecondaryBuffer + (Counter-Buffer);
  564. SecondaryCountAtSymbol += *(SecondaryBuffer + (Counter-Buffer));
  565. }
  566. memcpy( LastSymBuffer, symBuffer, sizeof(symBuffer) );
  567. UseLastSymbol = TRUE;
  568. }
  569. } else {
  570. if (CountAtSymbol || SecondaryCountAtSymbol) {
  571. if (!UseSecondaryProfile) {
  572. n= sprintf(Line,"%d,%wZ,%s (%08lx)\n",
  573. CountAtSymbol,
  574. ProfileObject[i].ImageName,
  575. LastSymbol->Name,
  576. LastSymbol->Address
  577. );
  578. } else {
  579. if (SecondaryCountAtSymbol != 0) {
  580. High = Percent(CountAtSymbol, SecondaryCountAtSymbol, &Low);
  581. n = sprintf(Line,"%d,%d,%2.2d.%3.3d,%wZ,%s (%08lx)\n",
  582. CountAtSymbol,
  583. SecondaryCountAtSymbol,
  584. High, Low,
  585. ProfileObject[i].ImageName,
  586. LastSymbol->Name,
  587. LastSymbol->Address
  588. );
  589. } else {
  590. n = sprintf(Line,"%d,%d, -- ,%wZ,%s (%08lx)\n",
  591. CountAtSymbol,
  592. SecondaryCountAtSymbol,
  593. ProfileObject[i].ImageName,
  594. LastSymbol->Name,
  595. LastSymbol->Address
  596. );
  597. }
  598. }
  599. PsWriteProfileLine(ProfileHandle,Line,n);
  600. if (ShowAllHits) {
  601. while (InitialCounter < Counter) {
  602. if (*InitialCounter) {
  603. Va = ((PUCHAR)InitialCounter - (PUCHAR)Buffer);
  604. Va = Va * (1 << (ProfileObject[i].BucketSize - 2));
  605. Va = Va + (ULONG_PTR)ProfileObject[i].CodeStart;
  606. if (!UseSecondaryProfile) {
  607. n = sprintf(Line, "\t%p:%d\n",
  608. Va,
  609. *InitialCounter);
  610. } else {
  611. if (*SecondaryInitialCounter != 0) {
  612. High = Percent(*InitialCounter, *SecondaryInitialCounter, &Low);
  613. n = sprintf(Line, "\t%p:%d, %d, %2.2d.%3.3d\n",
  614. Va,
  615. *InitialCounter,
  616. *SecondaryInitialCounter,
  617. High,Low);
  618. } else {
  619. n = sprintf(Line, "\t%p:%d, %d, --\n",
  620. Va,
  621. *InitialCounter,
  622. *SecondaryInitialCounter);
  623. }
  624. }
  625. PsWriteProfileLine(ProfileHandle, Line, n);
  626. }
  627. ++InitialCounter;
  628. ++SecondaryInitialCounter;
  629. }
  630. }
  631. InitialCounter = Counter;
  632. CountAtSymbol = *Counter;
  633. if (UseSecondaryProfile) {
  634. SecondaryInitialCounter = SecondaryBuffer + (Counter-Buffer);
  635. SecondaryCountAtSymbol += *(SecondaryBuffer + (Counter-Buffer));
  636. }
  637. memcpy( LastSymBuffer, BadSymBuffer, sizeof(BadSymBuffer) );
  638. UseLastSymbol = TRUE;
  639. }
  640. else {
  641. n = sprintf(Line,"%d,%wZ,Unknown (%p)\n",
  642. CountAtSymbol,
  643. ProfileObject[i].ImageName,
  644. Va
  645. );
  646. PsWriteProfileLine(ProfileHandle, Line, n);
  647. }
  648. }
  649. }
  650. }
  651. if ( CountAtSymbol || SecondaryCountAtSymbol ) {
  652. if (!UseSecondaryProfile) {
  653. n= sprintf(Line,"%d,%wZ,%s (%08lx)\n",
  654. CountAtSymbol,
  655. ProfileObject[i].ImageName,
  656. LastSymbol->Name,
  657. LastSymbol->Address
  658. );
  659. } else {
  660. if (SecondaryCountAtSymbol != 0) {
  661. High = Percent(CountAtSymbol, SecondaryCountAtSymbol, &Low);
  662. n = sprintf(Line,"%d,%d,%2.2d.%3.3d,%wZ,%s (%08lx)\n",
  663. CountAtSymbol,
  664. SecondaryCountAtSymbol,
  665. High, Low,
  666. ProfileObject[i].ImageName,
  667. LastSymbol->Name,
  668. LastSymbol->Address
  669. );
  670. } else {
  671. n = sprintf(Line,"%d,%d, -- ,%wZ,%s (%08lx)\n",
  672. CountAtSymbol,
  673. SecondaryCountAtSymbol,
  674. ProfileObject[i].ImageName,
  675. LastSymbol->Name,
  676. LastSymbol->Address
  677. );
  678. }
  679. }
  680. PsWriteProfileLine(ProfileHandle,Line,n);
  681. if (ShowAllHits) {
  682. while (InitialCounter < Counter) {
  683. if (*InitialCounter) {
  684. Va = ((PUCHAR)InitialCounter - (PUCHAR)Buffer);
  685. Va = Va * (1 << (ProfileObject[i].BucketSize - 2));
  686. Va = Va + (ULONG_PTR)ProfileObject[i].CodeStart;
  687. if (!UseSecondaryProfile) {
  688. n = sprintf(Line, "\t%p:%d\n",
  689. Va,
  690. *InitialCounter);
  691. } else {
  692. if (*SecondaryInitialCounter != 0) {
  693. High = Percent(*InitialCounter, *SecondaryInitialCounter, &Low);
  694. n = sprintf(Line, "\t%p:%d, %d, %2.2d.%3.3d\n",
  695. Va,
  696. *InitialCounter,
  697. *SecondaryInitialCounter,
  698. High, Low);
  699. } else {
  700. n = sprintf(Line, "\t%p:%d, %d, --\n",
  701. Va,
  702. *InitialCounter,
  703. *SecondaryInitialCounter);
  704. }
  705. }
  706. PsWriteProfileLine(ProfileHandle, Line, n);
  707. }
  708. ++InitialCounter;
  709. ++SecondaryInitialCounter;
  710. }
  711. }
  712. }
  713. SymUnloadModule( SYM_HANDLE, (DWORD_PTR)ProfileObject[i].ImageBase);
  714. }
  715. }
  716. for (i = 0; i < NumberOfProfileObjects; i++) {
  717. Buffer = ProfileObject[i].Buffer;
  718. RtlZeroMemory(Buffer,ProfileObject[i].BufferSize);
  719. }
  720. CloseHandle(ProfileHandle);
  721. } __except (EXCEPTION_EXECUTE_HANDLER) {
  722. }
  723. return STATUS_SUCCESS;
  724. }
  725. BOOLEAN
  726. DllMain(
  727. IN PVOID DllHandle,
  728. IN ULONG Reason,
  729. IN PCONTEXT Context OPTIONAL
  730. )
  731. {
  732. switch ( Reason ) {
  733. case DLL_PROCESS_ATTACH:
  734. DisableThreadLibraryCalls(DllHandle);
  735. if ( NtCurrentPeb()->ProcessParameters->Flags & RTL_USER_PROC_PROFILE_USER ) {
  736. PsParseCommandLine();
  737. PsInitializeAndStartProfile();
  738. }
  739. break;
  740. case DLL_PROCESS_DETACH:
  741. if ( NtCurrentPeb()->ProcessParameters->Flags & RTL_USER_PROC_PROFILE_USER ) {
  742. PsStopAndAnalyzeProfile();
  743. }
  744. break;
  745. }
  746. return TRUE;
  747. }
  748. char *
  749. Mystrtok (
  750. char * string,
  751. const char * control
  752. )
  753. {
  754. unsigned char *str;
  755. const unsigned char *ctrl = control;
  756. unsigned char map[32];
  757. int count;
  758. static char *nextoken;
  759. /* Clear control map */
  760. for (count = 0; count < 32; count++)
  761. map[count] = 0;
  762. /* Set bits in delimiter table */
  763. do {
  764. map[*ctrl >> 3] |= (1 << (*ctrl & 7));
  765. } while (*ctrl++);
  766. /* Initialize str. If string is NULL, set str to the saved
  767. * pointer (i.e., continue breaking tokens out of the string
  768. * from the last strtok call) */
  769. if (string)
  770. str = string;
  771. else
  772. str = nextoken;
  773. /* Find beginning of token (skip over leading delimiters). Note that
  774. * there is no token iff this loop sets str to point to the terminal
  775. * null (*str == '\0') */
  776. while ( (map[*str >> 3] & (1 << (*str & 7))) && *str )
  777. str++;
  778. string = str;
  779. /* Find the end of the token. If it is not the end of the string,
  780. * put a null there. */
  781. for ( ; *str ; str++ )
  782. if ( map[*str >> 3] & (1 << (*str & 7)) ) {
  783. *str++ = '\0';
  784. break;
  785. }
  786. /* Update nextoken (or the corresponding field in the per-thread data
  787. * structure */
  788. nextoken = str;
  789. /* Determine if a token has been found. */
  790. if ( string == str )
  791. return NULL;
  792. else
  793. return string;
  794. }
  795. VOID
  796. PsParseCommandLine(
  797. VOID
  798. )
  799. {
  800. PCHAR CommandLine;
  801. PCHAR Argument;
  802. HANDLE MappingHandle;
  803. PPROFILE_SOURCE_MAPPING ProfileMapping;
  804. //
  805. // The original command line is in a shared memory section
  806. // named "ProfileStartupParameters"
  807. //
  808. MappingHandle = OpenFileMapping(FILE_MAP_WRITE,
  809. FALSE,
  810. "ProfileStartupParameters");
  811. if (MappingHandle != NULL) {
  812. CommandLine = MapViewOfFile(MappingHandle,
  813. FILE_MAP_WRITE,
  814. 0,
  815. 0,
  816. 0);
  817. if (!CommandLine) {
  818. CloseHandle(MappingHandle);
  819. return;
  820. }
  821. } else {
  822. return;
  823. }
  824. Argument = Mystrtok(CommandLine," \t");
  825. while (Argument != NULL) {
  826. if ((Argument[0] == '-') ||
  827. (Argument[0] == '/')) {
  828. switch (Argument[1]) {
  829. case 'a':
  830. case 'A':
  831. ShowAllHits = TRUE;
  832. break;
  833. case 'b':
  834. case 'B':
  835. PowerOfBytesCoveredPerBucket = atoi(&Argument[2]);
  836. break;
  837. case 'f':
  838. case 'F':
  839. //
  840. // The arg area is unmapped so we copy the string
  841. //
  842. OutputFile = HeapAlloc(GetProcessHeap(), 0,
  843. lstrlen(&Argument[2]) + 1);
  844. lstrcpy(OutputFile, &Argument[2]);
  845. case 'i':
  846. case 'I':
  847. ProfileInterval = atoi(&Argument[2]);
  848. break;
  849. case 'k':
  850. case 'K':
  851. fKernel = TRUE;
  852. break;
  853. case 's':
  854. ProfileMapping = ProfileSourceMapping;
  855. while (ProfileMapping->Name != NULL) {
  856. if (_stricmp(ProfileMapping->Name, &Argument[2])==0) {
  857. ProfileSource = ProfileMapping->Source;
  858. break;
  859. }
  860. ++ProfileMapping;
  861. }
  862. break;
  863. case 'S':
  864. ProfileMapping = ProfileSourceMapping;
  865. while (ProfileMapping->Name != NULL) {
  866. if (_stricmp(ProfileMapping->Name, &Argument[2])==0) {
  867. SecondaryProfileSource = ProfileMapping->Source;
  868. UseSecondaryProfile = TRUE;
  869. break;
  870. }
  871. ++ProfileMapping;
  872. }
  873. break;
  874. }
  875. }
  876. Argument = Mystrtok(NULL," \t");
  877. }
  878. UnmapViewOfFile(CommandLine);
  879. CloseHandle(MappingHandle);
  880. }