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.

717 lines
19 KiB

  1. /*++
  2. Copyright (c) 1996-2000 Microsoft Corporation
  3. Module Name:
  4. dumpcd.c
  5. Abstract:
  6. This module dumps the contents of the
  7. entrypoint tree and translation cache to a file.
  8. Author:
  9. Dave Hastings (daveh) creation-date 02-May-1996
  10. Revision History:
  11. --*/
  12. #ifdef CODEGEN_PROFILE
  13. #include <nt.h>
  14. #include <ntrtl.h>
  15. #include <nturtl.h>
  16. #include <windows.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <entrypt.h>
  20. #include <coded.h>
  21. extern PEPNODE intelRoot;
  22. extern EPNODE _NIL;
  23. ULONG ProfileFlags = 0;
  24. BOOL
  25. ProcessEntrypoint(
  26. PENTRYPOINT Entrypoint
  27. );
  28. #define CODE_BUFFER_SIZE 8184
  29. UCHAR IntelCodeBuffer[CODE_BUFFER_SIZE];
  30. ULONG NativeCodeBuffer[CODE_BUFFER_SIZE];
  31. #define STACK_DEPTH 200
  32. ULONG DumpStack[STACK_DEPTH];
  33. ULONG DumpStackTop;
  34. #define STACK_RESET() DumpStackTop=0;
  35. #define PUSH(x) { \
  36. if (DumpStackTop == STACK_DEPTH-1) { \
  37. CHAR ErrorString[80]; \
  38. sprintf(ErrorString, "Error: Dump stack overflow\n"); \
  39. OutputDebugString(ErrorString); \
  40. goto Exit; \
  41. } else { \
  42. DumpStack[DumpStackTop] = x; \
  43. DumpStackTop++; \
  44. } \
  45. }
  46. #define POP(x) { \
  47. if (DumpStackTop == 0) { \
  48. CHAR ErrorString[80]; \
  49. sprintf(ErrorString, "Error: Dump stack underflow\n"); \
  50. OutputDebugString(ErrorString); \
  51. goto Exit; \
  52. } else { \
  53. DumpStackTop--; \
  54. x = DumpStack[DumpStackTop]; \
  55. } \
  56. }
  57. BOOL CpuCodegenProfile = FALSE;
  58. PCHAR CpuCodegenProfilePath = NULL;
  59. HANDLE CpuCodegenProfileFile = INVALID_HANDLE_VALUE;
  60. //
  61. // Code Description file state
  62. //
  63. ULONG CurrentFileLocation;
  64. ULONG CodeDescriptionFlags = 0;
  65. VOID
  66. InitCodegenProfile(
  67. VOID
  68. )
  69. /*++
  70. Routine Description:
  71. This routine gets the configuration information from the registry
  72. and creates the file to put the profile data into.
  73. Arguments:
  74. None.
  75. Return Value:
  76. None.
  77. --*/
  78. {
  79. LONG RetVal;
  80. DWORD KeyType;
  81. DWORD ProfileEnabled;
  82. DWORD BufferSize;
  83. CHAR FileName[MAX_PATH];
  84. LPTSTR CommandLine;
  85. CODEDESCRIPTIONHEADER Header;
  86. ULONG CommandLineLength;
  87. ULONG BytesWritten;
  88. BOOL Success;
  89. HKEY Key;
  90. //
  91. // Find out if codegen profiling is enabled. If there is a problem
  92. // with the value in the registry, we will be disabled by default.
  93. //
  94. RetVal = RegOpenKeyEx(
  95. HKEY_LOCAL_MACHINE,
  96. "System\\CurrentControlSet\\Control\\Wx86",
  97. 0,
  98. KEY_READ,
  99. &Key
  100. );
  101. BufferSize = sizeof(ProfileEnabled);
  102. RetVal = RegQueryValueEx(
  103. Key,
  104. "CpuCodegenProfile",
  105. NULL,
  106. &KeyType,
  107. (PVOID)&ProfileEnabled,
  108. &BufferSize
  109. );
  110. if ((RetVal != ERROR_SUCCESS) || (KeyType != REG_DWORD)) {
  111. OutputDebugString("Wx86Cpu: No CpuCodegenProfile value, or wrong type\n");
  112. return;
  113. }
  114. CpuCodegenProfile = ProfileEnabled;
  115. //
  116. // Get the path to store the datafile to.
  117. // First we get the size of the string (and verify that it is a string)
  118. // Then we get the actual string.
  119. //
  120. BufferSize = 0;
  121. RetVal = RegQueryValueEx(
  122. Key,
  123. "CpuCodegenProfilePath",
  124. NULL,
  125. &KeyType,
  126. (PVOID)&ProfileEnabled,
  127. &BufferSize
  128. );
  129. if ((RetVal != ERROR_MORE_DATA) || (KeyType != REG_SZ)) {
  130. OutputDebugString("Wx86Cpu: Problem with CpuCodegenProfilePath\n");
  131. CpuCodegenProfile = FALSE;
  132. return;
  133. }
  134. CpuCodegenProfilePath = HeapAlloc(GetProcessHeap(), 0, BufferSize);
  135. if (CpuCodegenProfilePath == NULL) {
  136. OutputDebugString("Wx86Cpu: Can't allocate CpuCodegenProfilePath\n");
  137. CpuCodegenProfile = FALSE;
  138. return;
  139. }
  140. RetVal = RegQueryValueEx(
  141. Key,
  142. "CpuCodegenProfilePath",
  143. NULL,
  144. &KeyType,
  145. CpuCodegenProfilePath,
  146. &BufferSize
  147. );
  148. if ((RetVal != ERROR_SUCCESS) || (KeyType != REG_SZ)) {
  149. //
  150. // Something really bad just happened. Don't do the profiling
  151. //
  152. OutputDebugString("Wx86Cpu: Inexplicable problem with CpuCodegenProfilePath\n");
  153. HeapFree(GetProcessHeap(), 0, CpuCodegenProfilePath);
  154. CpuCodegenProfile = FALSE;
  155. return;
  156. }
  157. //
  158. // Create file for the data
  159. //
  160. RetVal = GetTempFileName(CpuCodegenProfilePath, "prf", 0, FileName);
  161. if (RetVal == 0) {
  162. OutputDebugString("Wx86Cpu: GetTempFileName failed\n");
  163. HeapFree(GetProcessHeap(), 0, CpuCodegenProfilePath);
  164. CpuCodegenProfile = FALSE;
  165. return;
  166. }
  167. CpuCodegenProfileFile = CreateFile(
  168. FileName,
  169. GENERIC_WRITE,
  170. 0,
  171. NULL,
  172. TRUNCATE_EXISTING,
  173. FILE_ATTRIBUTE_COMPRESSED,
  174. NULL
  175. );
  176. if (CpuCodegenProfileFile == INVALID_HANDLE_VALUE) {
  177. OutputDebugString("Wx86Cpu: Unable to create profile file\n");
  178. HeapFree(GetProcessHeap(), 0, CpuCodegenProfilePath);
  179. CpuCodegenProfile = FALSE;
  180. return;
  181. }
  182. //
  183. // Write the file header to the file
  184. //
  185. CommandLine = GetCommandLine();
  186. CommandLineLength = strlen(CommandLine) + 1;
  187. Header.CommandLineOffset = sizeof(CODEDESCRIPTIONHEADER);
  188. Header.NextCodeDescriptionOffset = ((sizeof(CODEDESCRIPTIONHEADER) +
  189. CommandLineLength) + 3) & ~3;
  190. Header.DumpFileRev = CODEGEN_PROFILE_REV;
  191. Header.StartTime = GetCurrentTime();
  192. Success = WriteFile(
  193. CpuCodegenProfileFile,
  194. &Header,
  195. sizeof(Header),
  196. &BytesWritten,
  197. NULL
  198. );
  199. if (!Success || (BytesWritten != sizeof(Header))) {
  200. OutputDebugString("Wx86Cpu: Failed to write profile header\n");
  201. CloseHandle(CpuCodegenProfileFile);
  202. HeapFree(GetProcessHeap(), 0, CpuCodegenProfilePath);
  203. CpuCodegenProfile = FALSE;
  204. return;
  205. }
  206. Success = WriteFile(
  207. CpuCodegenProfileFile,
  208. CommandLine,
  209. CommandLineLength,
  210. &BytesWritten,
  211. NULL
  212. );
  213. if (!Success || (BytesWritten != CommandLineLength)) {
  214. OutputDebugString("Wx86Cpu: Failed to write profile header\n");
  215. CloseHandle(CpuCodegenProfileFile);
  216. HeapFree(GetProcessHeap(), 0, CpuCodegenProfilePath);
  217. CpuCodegenProfile = FALSE;
  218. return;
  219. }
  220. //
  221. // Set the file position for the first code description
  222. //
  223. CurrentFileLocation = SetFilePointer(
  224. CpuCodegenProfileFile,
  225. Header.NextCodeDescriptionOffset,
  226. NULL,
  227. FILE_BEGIN
  228. );
  229. if (CurrentFileLocation != Header.NextCodeDescriptionOffset) {
  230. OutputDebugString("Wx86Cpu: failed to update file position\n");
  231. CloseHandle(CpuCodegenProfileFile);
  232. HeapFree(GetProcessHeap(), 0, CpuCodegenProfilePath);
  233. CpuCodegenProfile = FALSE;
  234. return;
  235. }
  236. }
  237. VOID
  238. TerminateCodegenProfile(
  239. VOID
  240. )
  241. /*++
  242. Routine Description:
  243. This function put in the terminating record and closes the file.
  244. Arguments:
  245. None
  246. Return Value:
  247. None.
  248. --*/
  249. {
  250. CODEDESCRIPTION CodeDescription;
  251. BOOL Success;
  252. ULONG BytesWritten;
  253. CHAR ErrorString[80];
  254. if (!CpuCodegenProfile) {
  255. return;
  256. }
  257. CodeDescription.NextCodeDescriptionOffset = 0xFFFFFFFF;
  258. CodeDescription.TypeTag = PROFILE_TAG_EOF;
  259. CodeDescription.CreationTime = GetCurrentTime();
  260. Success = WriteFile(
  261. CpuCodegenProfileFile,
  262. &CodeDescription,
  263. sizeof(CODEDESCRIPTION),
  264. &BytesWritten,
  265. NULL
  266. );
  267. if (!Success || (BytesWritten != sizeof(CODEDESCRIPTION))) {
  268. sprintf(
  269. ErrorString,
  270. "Error: Could not write termination record, %lu\n",
  271. ProxyGetLastError()
  272. );
  273. OutputDebugString(ErrorString);
  274. }
  275. CpuCodegenProfile = FALSE;
  276. CloseHandle(CpuCodegenProfileFile);
  277. }
  278. VOID
  279. DumpCodeDescriptions(
  280. BOOL TCFlush
  281. )
  282. /*++
  283. Routine Description:
  284. This routine dumps out the entrypoints, and the corresponding code
  285. to a file in binary form.
  286. Return Value:
  287. None.
  288. --*/
  289. {
  290. NTSTATUS Status;
  291. PEPNODE NextEntrypoint;
  292. EPNODE Entrypoint;
  293. ULONG Epcount = 0;
  294. if (!CpuCodegenProfile) {
  295. return;
  296. }
  297. //
  298. // Get the root of the entrypoint tree
  299. //
  300. NextEntrypoint = intelRoot;
  301. //
  302. // Initialize stack
  303. //
  304. STACK_RESET();
  305. PUSH(0);
  306. //
  307. // iterate over every entrypoint
  308. //
  309. while (NextEntrypoint != NULL) {
  310. Entrypoint = *NextEntrypoint;
  311. //
  312. // Process the top level entrypoint
  313. //
  314. if (!ProcessEntrypoint(&Entrypoint.ep)){
  315. goto Exit;
  316. }
  317. //
  318. // Process the sub entrypoints
  319. //
  320. while (Entrypoint.ep.SubEP) {
  321. Entrypoint.ep = *Entrypoint.ep.SubEP;
  322. //
  323. // Write the sub-entrypoint to the file
  324. //
  325. if (!ProcessEntrypoint(&Entrypoint.ep)){
  326. goto Exit;
  327. }
  328. }
  329. //
  330. // Set up for future iterations
  331. //
  332. if (Entrypoint.intelRight != &_NIL) {
  333. PUSH((ULONG)Entrypoint.intelRight);
  334. }
  335. if (Entrypoint.intelLeft != &_NIL) {
  336. PUSH((ULONG)Entrypoint.intelLeft);
  337. }
  338. POP((ULONG)NextEntrypoint);
  339. }
  340. Exit: ;
  341. if (TCFlush) {
  342. CODEDESCRIPTION CodeDescription;
  343. ULONG NextCodeDescriptionOffset;
  344. BOOL Success;
  345. ULONG BytesWritten;
  346. CHAR ErrorString[80];
  347. NextCodeDescriptionOffset = (CurrentFileLocation + sizeof(CODEDESCRIPTION)) & ~3;
  348. CodeDescription.TypeTag = PROFILE_TAG_TCFLUSH;
  349. CodeDescription.NextCodeDescriptionOffset = NextCodeDescriptionOffset;
  350. CodeDescription.CreationTime = GetCurrentTime();
  351. Success = WriteFile(
  352. CpuCodegenProfileFile,
  353. &CodeDescription,
  354. sizeof(CODEDESCRIPTION),
  355. &BytesWritten,
  356. NULL
  357. );
  358. if (!Success || (BytesWritten != sizeof(CODEDESCRIPTION))) {
  359. sprintf(
  360. ErrorString,
  361. "Error: Could not write code description, %lu\n",
  362. ProxyGetLastError()
  363. );
  364. OutputDebugString(ErrorString);
  365. return;
  366. }
  367. CurrentFileLocation = SetFilePointer(
  368. CpuCodegenProfileFile,
  369. NextCodeDescriptionOffset,
  370. NULL,
  371. FILE_BEGIN
  372. );
  373. if (CurrentFileLocation != (ULONG)NextCodeDescriptionOffset) {
  374. sprintf(ErrorString, "Error: SetFilePointer didn't work\n");
  375. OutputDebugString(ErrorString);
  376. return;
  377. }
  378. }
  379. }
  380. BOOL
  381. ProcessEntrypoint(
  382. PENTRYPOINT Entrypoint
  383. )
  384. /*++
  385. Routine Description:
  386. This routine writes the description for this entrypoint to the file.
  387. Arguments:
  388. Entrypoint -- Supplies the entrypoint to describe
  389. File -- Supplies the file to write to
  390. Return Value:
  391. True for success, False for failure
  392. --*/
  393. {
  394. ULONG NativeCodeLength, IntelCodeLength;
  395. CODEDESCRIPTION CodeDescription;
  396. ULONG NextCodeDescriptionOffset;
  397. NTSTATUS Status;
  398. BOOL Success;
  399. ULONG BytesWritten;
  400. CHAR ErrorString[80];
  401. //
  402. // Create the code description
  403. //
  404. NativeCodeLength = ((ULONG)Entrypoint->nativeEnd - (ULONG)Entrypoint->nativeStart + 4) & ~3;
  405. IntelCodeLength = (ULONG)Entrypoint->intelEnd - (ULONG)Entrypoint->intelStart + 1;
  406. CodeDescription.NativeCodeOffset = CurrentFileLocation + sizeof(CODEDESCRIPTION);
  407. CodeDescription.IntelCodeOffset = CodeDescription.NativeCodeOffset + NativeCodeLength;
  408. NextCodeDescriptionOffset = (CodeDescription.IntelCodeOffset +
  409. IntelCodeLength + 3) & ~3;
  410. CodeDescription.NextCodeDescriptionOffset = NextCodeDescriptionOffset;
  411. CodeDescription.IntelAddress = (ULONG)Entrypoint->intelStart;
  412. CodeDescription.NativeAddress = (ULONG)Entrypoint->nativeStart;
  413. CodeDescription.SequenceNumber = Entrypoint->SequenceNumber;
  414. CodeDescription.ExecutionCount = Entrypoint->ExecutionCount;
  415. CodeDescription.IntelCodeSize = IntelCodeLength;
  416. CodeDescription.NativeCodeSize = NativeCodeLength;
  417. CodeDescription.TypeTag = PROFILE_TAG_CODEDESCRIPTION;
  418. CodeDescription.CreationTime = Entrypoint->CreationTime;
  419. //
  420. // Verify that we can get all of the Intel and Native code
  421. //
  422. if (
  423. (IntelCodeLength / sizeof(IntelCodeBuffer[1]) > CODE_BUFFER_SIZE) ||
  424. (NativeCodeLength) && (NativeCodeLength / sizeof(NativeCodeBuffer[1]) > CODE_BUFFER_SIZE)
  425. ) {
  426. sprintf(ErrorString, "Error: Code buffers not big enough:N %lx:I %lx\n", NativeCodeLength, IntelCodeLength);
  427. OutputDebugString(ErrorString);
  428. return FALSE;
  429. }
  430. //
  431. // Get the native code
  432. //
  433. if (NativeCodeLength) {
  434. memcpy(NativeCodeBuffer, Entrypoint->nativeStart, NativeCodeLength);
  435. }
  436. //
  437. // Get the Intel code
  438. //
  439. try {
  440. memcpy(IntelCodeBuffer, Entrypoint->intelStart, IntelCodeLength);
  441. } except (EXCEPTION_EXECUTE_HANDLER) {
  442. //
  443. // Apparently the intel code is no longer there. This happens
  444. // if a dll gets unloaded
  445. //
  446. IntelCodeLength = 0;
  447. CodeDescription.IntelCodeSize = 0;
  448. CodeDescription.IntelCodeOffset = CodeDescription.NativeCodeOffset + NativeCodeLength;
  449. NextCodeDescriptionOffset = (CodeDescription.IntelCodeOffset +
  450. IntelCodeLength + 3) & ~3;
  451. CodeDescription.NextCodeDescriptionOffset = NextCodeDescriptionOffset;
  452. }
  453. //
  454. // Write code description to disk
  455. //
  456. Success = WriteFile(
  457. CpuCodegenProfileFile,
  458. &CodeDescription,
  459. sizeof(CODEDESCRIPTION),
  460. &BytesWritten,
  461. NULL
  462. );
  463. if (!Success || (BytesWritten != sizeof(CODEDESCRIPTION))) {
  464. sprintf(
  465. ErrorString,
  466. "Error: Could not write code description, %lu\n",
  467. ProxyGetLastError()
  468. );
  469. OutputDebugString(ErrorString);
  470. return FALSE;
  471. }
  472. //
  473. // Write Native code to disk
  474. //
  475. if (NativeCodeLength) {
  476. Success = WriteFile(
  477. CpuCodegenProfileFile,
  478. NativeCodeBuffer,
  479. NativeCodeLength,
  480. &BytesWritten,
  481. NULL
  482. );
  483. if (!Success || (BytesWritten != NativeCodeLength)) {
  484. sprintf(
  485. ErrorString,
  486. "Error: Could not write native code, %lu\n",
  487. ProxyGetLastError()
  488. );
  489. OutputDebugString(ErrorString);
  490. return FALSE;
  491. }
  492. }
  493. //
  494. // Write Intel code to disk
  495. //
  496. if (IntelCodeLength) {
  497. Success = WriteFile(
  498. CpuCodegenProfileFile,
  499. IntelCodeBuffer,
  500. IntelCodeLength,
  501. &BytesWritten,
  502. NULL
  503. );
  504. if (!Success || (BytesWritten != IntelCodeLength)) {
  505. sprintf(
  506. ErrorString,
  507. "Error: Could not write native code, %lu\n",
  508. ProxyGetLastError()
  509. );
  510. OutputDebugString(ErrorString);
  511. return FALSE;
  512. }
  513. }
  514. Success = WriteFile(
  515. CpuCodegenProfileFile,
  516. IntelCodeBuffer,
  517. IntelCodeLength,
  518. &BytesWritten,
  519. NULL
  520. );
  521. if (!Success || (BytesWritten != IntelCodeLength)) {
  522. sprintf(
  523. ErrorString,
  524. "Error: Could not write native code, %lu\n",
  525. ProxyGetLastError()
  526. );
  527. OutputDebugString(ErrorString);
  528. return FALSE;
  529. }
  530. //
  531. // Update file pointer position
  532. //
  533. CurrentFileLocation = SetFilePointer(
  534. CpuCodegenProfileFile,
  535. NextCodeDescriptionOffset,
  536. NULL,
  537. FILE_BEGIN
  538. );
  539. if (CurrentFileLocation != (ULONG)NextCodeDescriptionOffset) {
  540. sprintf(ErrorString, "Error: SetFilePointer didn't work\n");
  541. OutputDebugString(ErrorString);
  542. return FALSE;
  543. }
  544. return TRUE;
  545. }
  546. VOID
  547. DumpAllocFailure(
  548. VOID
  549. )
  550. /*++
  551. Routine Description:
  552. This routine adds an allocation failure record to the profile dump.
  553. Arguments:
  554. None.
  555. Return Value:
  556. None.
  557. --*/
  558. {
  559. CODEDESCRIPTION CodeDescription;
  560. BOOL Success;
  561. ULONG BytesWritten;
  562. CHAR ErrorString[80];
  563. ULONG NextCodeDescriptionOffset;
  564. if (!CpuCodegenProfile) {
  565. return;
  566. }
  567. NextCodeDescriptionOffset = CurrentFileLocation + sizeof(CODEDESCRIPTION);
  568. CodeDescription.NextCodeDescriptionOffset = NextCodeDescriptionOffset;
  569. CodeDescription.TypeTag = PROFILE_TAG_TCALLOCFAIL;
  570. CodeDescription.CreationTime = GetCurrentTime();
  571. Success = WriteFile(
  572. CpuCodegenProfileFile,
  573. &CodeDescription,
  574. sizeof(CODEDESCRIPTION),
  575. &BytesWritten,
  576. NULL
  577. );
  578. if (!Success || (BytesWritten != sizeof(CODEDESCRIPTION))) {
  579. sprintf(
  580. ErrorString,
  581. "Error: Could not write termination record, %lu\n",
  582. ProxyGetLastError()
  583. );
  584. OutputDebugString(ErrorString);
  585. }
  586. //
  587. // Update file pointer position
  588. //
  589. CurrentFileLocation = SetFilePointer(
  590. CpuCodegenProfileFile,
  591. NextCodeDescriptionOffset,
  592. NULL,
  593. FILE_BEGIN
  594. );
  595. if (CurrentFileLocation != (ULONG)NextCodeDescriptionOffset) {
  596. sprintf(ErrorString, "Error: SetFilePointer didn't work\n");
  597. OutputDebugString(ErrorString);
  598. }
  599. }
  600. #endif