Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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