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.

2269 lines
90 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. surface.cxx
  5. Abstract:
  6. This file contains the routines to page in surface data.
  7. Author:
  8. Jason Hartman (JasonHa) 2001-05-16
  9. Environment:
  10. User Mode
  11. --*/
  12. #include "precomp.hxx"
  13. #define STRSAFE_NO_DEPRECATE
  14. #include "strsafe.h"
  15. BYTE x86_jmp_here[] = { 0xeb, 0xfe }; // spin jmp
  16. BYTE x86_jmp_plus_0x0e[] = { 0xeb, 0x0e }; // jmp
  17. BYTE x86_jb_plus_0x02[] = { 0x72, 0x02 }; // je
  18. BYTE x86_jne_minus_0x18[] = { 0x75, 0xe7 }; // jne
  19. BYTE x86_jmp_plus_0x06[] = { 0xeb, 0x06 }; // jmp
  20. BYTE x86_jb_plus_0x0c[] = { 0x72, 0x0c }; // je
  21. BYTE x86_jnz_minus_0x08[] = { 0x75, 0xf8 }; // jne
  22. #define I_START_IP 0x00000001
  23. #define I_WRITE_ADDRESS 0x00000002
  24. typedef struct _Instruction {
  25. FLONG Flags;
  26. ULONG ByteLen;
  27. PSTR Code;
  28. } Instruction;
  29. /******************************Public*Routine******************************\
  30. * SURFACE
  31. *
  32. \**************************************************************************/
  33. DECLARE_API( surface )
  34. {
  35. BEGIN_API( surface );
  36. HRESULT hr = S_OK;
  37. ULONG64 SurfAddr;
  38. DEBUG_VALUE Arg;
  39. BOOL BadSwitch = FALSE;
  40. BOOL AddressIsSURFOBJ = FALSE;
  41. BOOL AddressIsSURFACE = FALSE;
  42. BOOL ArgumentIsHandle = FALSE;
  43. OutputControl OutCtl(Client);
  44. while (!BadSwitch)
  45. {
  46. while (isspace(*args)) args++;
  47. if (*args != '-') break;
  48. args++;
  49. BadSwitch = (*args == '\0' || isspace(*args));
  50. while (*args != '\0' && !isspace(*args))
  51. {
  52. switch (tolower(*args))
  53. {
  54. case 'a':
  55. if (ArgumentIsHandle || AddressIsSURFOBJ)
  56. {
  57. OutCtl.OutErr("Error: Only one of -a, -h, or -o may be specified.\n");
  58. BadSwitch = TRUE;
  59. }
  60. else
  61. {
  62. AddressIsSURFACE = TRUE;
  63. }
  64. break;
  65. case 'h':
  66. if (AddressIsSURFACE || AddressIsSURFOBJ)
  67. {
  68. OutCtl.OutErr("Error: Only one of -a, -h, or -o may be specified.\n");
  69. BadSwitch = TRUE;
  70. }
  71. else
  72. {
  73. ArgumentIsHandle = TRUE;
  74. }
  75. break;
  76. case 'o':
  77. if (ArgumentIsHandle || AddressIsSURFACE)
  78. {
  79. OutCtl.OutErr("Error: Only one of -a, -h, or -o may be specified.\n");
  80. BadSwitch = TRUE;
  81. }
  82. else
  83. {
  84. AddressIsSURFOBJ = TRUE;
  85. }
  86. break;
  87. default:
  88. BadSwitch = TRUE;
  89. break;
  90. }
  91. if (BadSwitch) break;
  92. args++;
  93. }
  94. }
  95. if (BadSwitch ||
  96. (hr = Evaluate(Client, args, DEBUG_VALUE_INT64, 0, &Arg, NULL)) != S_OK ||
  97. Arg.I64 == 0)
  98. {
  99. OutCtl.Output("Usage: surface [-?] < [-h] HSURF | [-a] SURFACE Addr | -o SURFOBJ Addr>\n"
  100. "\n"
  101. " Note: HBITMAP is the same as HSURF.\n");
  102. }
  103. else
  104. {
  105. if (AddressIsSURFOBJ)
  106. {
  107. PDEBUG_SYMBOLS Symbols;
  108. ULONG64 SurfModule;
  109. ULONG SurfTypeId;
  110. ULONG BaseObjTypeId;
  111. ULONG SurfObjOffset;
  112. if ((hr = Client->QueryInterface(__uuidof(IDebugSymbols),
  113. (void **)&Symbols)) == S_OK)
  114. {
  115. // Try to read SURFOBJ offset from SURFACE type, but
  116. // if that fails assume it is directly after BASEOBJECT.
  117. if ((hr = GetTypeId(Client, "SURFACE", &SurfTypeId, &SurfModule)) != S_OK ||
  118. (hr = Symbols->GetFieldOffset(SurfModule, SurfTypeId, "so", &SurfObjOffset)) != S_OK)
  119. {
  120. if ((hr = Symbols->GetTypeId(Type_Module.Base, "_BASEOBJECT", &BaseObjTypeId)) == S_OK)
  121. {
  122. hr = Symbols->GetTypeSize(Type_Module.Base, BaseObjTypeId, &SurfObjOffset);
  123. }
  124. }
  125. Symbols->Release();
  126. }
  127. if (hr != S_OK)
  128. {
  129. OutCtl.OutErr("Error: SURFOBJ to SURFACE lookup failed.\n");
  130. }
  131. else
  132. {
  133. SurfAddr = Arg.I64 - SurfObjOffset;
  134. }
  135. }
  136. else if (AddressIsSURFACE)
  137. {
  138. SurfAddr = Arg.I64;
  139. }
  140. else
  141. {
  142. // Try to look value up as a SURFACE handle
  143. hr = GetObjectAddress(Client, Arg.I64, &SurfAddr, SURF_TYPE, TRUE, TRUE);
  144. if (hr != S_OK || SurfAddr == 0)
  145. {
  146. if (ArgumentIsHandle)
  147. {
  148. OutCtl.OutErr(" 0x%p is not a valid HSURF\n", Arg.I64);
  149. }
  150. else
  151. {
  152. // The value wasn't restricted to a handle
  153. // so try as a SURFACE address.
  154. SurfAddr = Arg.I64;
  155. hr = S_OK;
  156. }
  157. }
  158. else
  159. {
  160. ArgumentIsHandle = TRUE;
  161. }
  162. }
  163. if (hr == S_OK && !ArgumentIsHandle)
  164. {
  165. DEBUG_VALUE ObjHandle;
  166. TypeOutputParser TypeParser(Client);
  167. OutputState OutState(Client);
  168. ULONG64 SurfAddrFromHmgr;
  169. if ((hr = OutState.Setup(0, &TypeParser)) != S_OK ||
  170. (hr = OutState.OutputTypeVirtual(SurfAddr, "SURFACE", 0)) != S_OK ||
  171. (hr = TypeParser.Get(&ObjHandle, "hHmgr", DEBUG_VALUE_INT64)) != S_OK)
  172. {
  173. OutCtl.OutErr("Unable to get contents of SURFACE::hHmgr\n");
  174. OutCtl.OutErr(" (Type Read returned %s)\n", pszHRESULT(hr));
  175. if (AddressIsSURFOBJ)
  176. {
  177. OutCtl.OutErr(" 0x%p is not a valid SURFOBJ address\n", Arg.I64);
  178. }
  179. else if (AddressIsSURFACE)
  180. {
  181. OutCtl.OutErr(" 0x%p is not a valid SURFACE address\n", Arg.I64);
  182. }
  183. else
  184. {
  185. OutCtl.OutErr(" 0x%p is neither an HSURF nor valid SURFACE address\n", Arg.I64);
  186. }
  187. }
  188. else
  189. {
  190. if (GetObjectAddress(Client, ObjHandle.I64, &SurfAddrFromHmgr,
  191. SURF_TYPE, TRUE, FALSE) == S_OK &&
  192. SurfAddrFromHmgr != SurfAddr)
  193. {
  194. OutCtl.OutWarn("\tNote: SURFACE may not be valid.\n"
  195. "\t It does not have a valid handle manager entry.\n");
  196. }
  197. }
  198. }
  199. if (hr == S_OK)
  200. {
  201. hr = DumpType(Client, "SURFACE", SurfAddr);
  202. if (hr != S_OK)
  203. {
  204. OutCtl.OutErr("Type Dump for SURFACE returned %s.\n", pszHRESULT(hr));
  205. }
  206. }
  207. }
  208. EXIT_API(hr);
  209. }
  210. DECLARE_API( dpso )
  211. {
  212. INIT_API();
  213. ExtOut("Obsolete: Use 'surfobj <SURFOBJ Addr>'.\n");
  214. EXIT_API(S_OK);
  215. }
  216. /******************************Public*Routine******************************\
  217. * SURFLIST
  218. *
  219. * List readable surfaces and brief info
  220. *
  221. \**************************************************************************/
  222. PCSTR SurfaceListFields[] = {
  223. "so.hsurf",
  224. "so.hdev",
  225. "so.sizlBitmap",
  226. "so.cjBits",
  227. "so.pvBits",
  228. "so.iBitmapFormat",
  229. "so.iType",
  230. "so.fjBitmap",
  231. NULL
  232. };
  233. PCSTR ExtendedSurfaceListFields[] = {
  234. "ulShareCount",
  235. "BaseFlags",
  236. "so.dhsurf",
  237. "SurfFlags",
  238. NULL
  239. };
  240. DECLARE_API( surflist )
  241. {
  242. BEGIN_API( surflist );
  243. HRESULT hr;
  244. HRESULT hrMask;
  245. ULONG64 index = 0;
  246. ULONG64 gcMaxHmgr;
  247. ULONG64 SurfAddr;
  248. BOOL BadSwitch = FALSE;
  249. BOOL DumpBaseObject = FALSE;
  250. BOOL DumpExtended = FALSE;
  251. BOOL DumpUserFields = FALSE;
  252. OutputControl OutCtl(Client);
  253. while (!BadSwitch)
  254. {
  255. while (isspace(*args)) args++;
  256. if (*args != '-') break;
  257. args++;
  258. BadSwitch = (*args == '\0' || isspace(*args));
  259. while (*args != '\0' && !isspace(*args))
  260. {
  261. switch (*args)
  262. {
  263. case 'b': DumpBaseObject = TRUE; break;
  264. case 'e': DumpExtended = TRUE; break;
  265. default:
  266. BadSwitch = TRUE;
  267. break;
  268. }
  269. if (BadSwitch) break;
  270. args++;
  271. }
  272. }
  273. if (BadSwitch)
  274. {
  275. OutCtl.Output("Usage: surflist [-?be] [<Start Index>] [<Member List>]\n"
  276. "\n"
  277. " b - Dump BASEOBJECT information\n"
  278. " e - Dump extended members\n"
  279. " ulShareCount, BaseFlags, dhsurf, SurfFlags\n"
  280. "\n"
  281. " Start Index - First hmgr entry index to begin listing\n"
  282. " Member List - Space seperated list of other SURFACE members\n"
  283. " to be included in the dump\n");
  284. return S_OK;
  285. }
  286. DEBUG_VALUE dvIndex;
  287. ULONG RemIndex;
  288. if (*args != '\0' && !iscsymf(*args) &&
  289. ((hr = Evaluate(Client, args, DEBUG_VALUE_INT64, 0, &dvIndex, &RemIndex)) == S_OK))
  290. {
  291. index = dvIndex.I64;
  292. args += RemIndex;
  293. // Always keep args at the next unhandled argument
  294. while (isspace(*args)) args++;
  295. }
  296. if ((hr = GetMaxHandles(Client, &gcMaxHmgr)) != S_OK)
  297. {
  298. OutCtl.OutErr("Unable to get sizeof GDI handle table. HRESULT %s\n", pszHRESULT(hr));
  299. return hr;
  300. }
  301. gcMaxHmgr = (ULONG64)(ULONG)gcMaxHmgr;
  302. if (index != 0 && index >= gcMaxHmgr)
  303. {
  304. OutCtl.Output("No remaining handle entries to be searched.\n");
  305. return hr;
  306. }
  307. OutCtl.Output("Searching %s 0x%I64x handle entries for Surfaces.\n",
  308. (index ? "remaining" : "all"), gcMaxHmgr - index);
  309. OutputFilter OutFilter(Client);
  310. OutputState OutState(Client, FALSE);
  311. OutputControl OutCtlToFilter;
  312. ULONG64 Module;
  313. ULONG TypeId;
  314. ULONG OutputMask;
  315. BOOL IsPointer64Bit;
  316. ULONG PointerSize;
  317. if ((hr = OutState.Setup(DEBUG_OUTPUT_NORMAL,
  318. &OutFilter)) == S_OK &&
  319. (hr = OutCtlToFilter.SetControl(DEBUG_OUTCTL_THIS_CLIENT |
  320. DEBUG_OUTCTL_NOT_LOGGED,
  321. OutState.Client)) == S_OK &&
  322. (hr = GetTypeId(Client, "SURFACE", &TypeId, &Module)) == S_OK)
  323. {
  324. TypeOutputDumper TypeReader(OutState.Client, &OutCtlToFilter);
  325. TypeReader.SelectMarks(1);
  326. TypeReader.IncludeMarked();
  327. if (DumpBaseObject) TypeReader.MarkFields(BaseObjectFields);
  328. if (DumpExtended) TypeReader.MarkFields(ExtendedSurfaceListFields);
  329. // Add user specified fields to dump list
  330. PSTR MemberList = NULL;
  331. CHAR *pBOF = (CHAR *)args;
  332. if (iscsymf(*pBOF))
  333. {
  334. MemberList = (PSTR) HeapAlloc(GetProcessHeap(), 0, strlen(pBOF)+1);
  335. if (MemberList != NULL)
  336. {
  337. strcpy(MemberList, pBOF);
  338. pBOF = MemberList;
  339. DumpUserFields = TRUE;
  340. while (iscsymf(*pBOF))
  341. {
  342. CHAR *pEOF = pBOF;
  343. CHAR EOFChar;
  344. // Get member
  345. do {
  346. pEOF++;
  347. } while (iscsym(*pEOF) || *pEOF == '.' || *pEOF == '*');
  348. EOFChar = *pEOF;
  349. *pEOF = '\0';
  350. TypeReader.MarkField(pBOF);
  351. // Advance to next
  352. if (EOFChar != '\0')
  353. {
  354. do
  355. {
  356. pEOF++;
  357. } while (isspace(*pEOF));
  358. }
  359. pBOF = pEOF;
  360. }
  361. }
  362. else
  363. {
  364. OutCtl.OutErr("Error: Couldn't allocate memory for Member List.\n");
  365. hr = E_OUTOFMEMORY;
  366. }
  367. }
  368. if (hr == S_OK && *pBOF != '\0')
  369. {
  370. OutCtl.OutErr("Error: \"%s\" is not a valid member list.\n", pBOF);
  371. hr = E_INVALIDARG;
  372. }
  373. if (hr == S_OK)
  374. {
  375. // Setup default dump specifications
  376. TypeReader.SelectMarks(0);
  377. TypeReader.IncludeMarked();
  378. TypeReader.MarkFields(SurfaceListFields);
  379. OutFilter.Replace(OUTFILTER_REPLACE_THIS, " so _SURFOBJ ", NULL);
  380. OutFilter.Replace(OUTFILTER_REPLACE_THIS, " hsurf ", NULL);
  381. OutFilter.Replace(OUTFILTER_REPLACE_THIS, " hdev ", NULL);
  382. OutFilter.Replace(OUTFILTER_REPLACE_THIS, "(null)", "(null) ");
  383. OutFilter.Replace(OUTFILTER_REPLACE_THIS, " sizlBitmap", NULL);
  384. OutFilter.Replace(OUTFILTER_REPLACE_THIS, " cjBits", NULL);
  385. OutFilter.Replace(OUTFILTER_REPLACE_THIS, " pvBits", NULL);
  386. OutFilter.Replace(OUTFILTER_REPLACE_THIS, " iBitmapFormat", NULL);
  387. OutFilter.Replace(OUTFILTER_REPLACE_THIS, " iType", NULL);
  388. OutFilter.Replace(OUTFILTER_REPLACE_THIS, " fjBitmap", NULL);
  389. // Output dump header
  390. PointerSize = (OutCtl.IsPointer64Bit() == S_OK) ? 21 : 10;
  391. OutCtl.Output(" %-*s HSURF HDEV Dimensions cjBits %-*s Format\t\t\t",
  392. PointerSize, "&SURFACE", PointerSize, "pvBits");
  393. if (DumpBaseObject) OutCtl.Output(" \tBASEOBJECT");
  394. if (DumpExtended) OutCtl.Output(" ulShareCount BaseFlags dhsurf SurfFlags");
  395. if (DumpUserFields) OutCtl.Output(" %s", args);
  396. OutCtl.Output("\n");
  397. for (; index < gcMaxHmgr; index++)
  398. {
  399. if (OutCtl.GetInterrupt() == S_OK) break;
  400. // Turn off error and verbose messages for this call to
  401. // GetObjectAddress since it will spew for non-surfaces.
  402. if ((hrMask = Client->GetOutputMask(&OutputMask)) == S_OK &&
  403. OutputMask & (DEBUG_OUTPUT_ERROR | DEBUG_OUTPUT_VERBOSE))
  404. {
  405. hrMask = Client->SetOutputMask(OutputMask & ~(DEBUG_OUTPUT_ERROR | DEBUG_OUTPUT_VERBOSE));
  406. }
  407. hr = GetObjectAddress(Client, index, &SurfAddr, SURF_TYPE, FALSE, FALSE);
  408. // Restore mask
  409. if (hrMask == S_OK &&
  410. OutputMask & (DEBUG_OUTPUT_ERROR | DEBUG_OUTPUT_VERBOSE))
  411. {
  412. Client->SetOutputMask(OutputMask);
  413. }
  414. if (hr != S_OK || SurfAddr == 0) continue;
  415. OutCtl.Output(" 0x%p ", SurfAddr);
  416. // Read to fields to OutFilter: 'ppdevNext' and 'fl'
  417. OutFilter.DiscardOutput();
  418. hr = TypeReader.OutputVirtual(Module, TypeId, SurfAddr,
  419. DEBUG_OUTTYPE_NO_OFFSET |
  420. DEBUG_OUTTYPE_COMPACT_OUTPUT);
  421. if (hr == S_OK)
  422. {
  423. if (DumpBaseObject || DumpExtended || DumpUserFields)
  424. {
  425. OutCtlToFilter.Output(" \t");
  426. TypeReader.SelectMarks(1);
  427. TypeReader.OutputVirtual(Module, TypeId, SurfAddr,
  428. DEBUG_OUTTYPE_NO_OFFSET |
  429. DEBUG_OUTTYPE_COMPACT_OUTPUT);
  430. TypeReader.SelectMarks(0);
  431. }
  432. OutFilter.OutputText(&OutCtl, DEBUG_OUTPUT_NORMAL);
  433. OutCtl.Output("\n");
  434. }
  435. else
  436. {
  437. OutCtl.Output("0x????%4.4I64x ** failed to read surface **\n", index);
  438. }
  439. }
  440. hr = S_OK;
  441. }
  442. if (MemberList != NULL)
  443. {
  444. HeapFree(GetProcessHeap(), 0, MemberList);
  445. }
  446. }
  447. else
  448. {
  449. OutCtl.OutErr(" Output state/control setup returned %s.\n",
  450. pszHRESULT(hr));
  451. }
  452. return hr;
  453. }
  454. /******************************Public*Routine******************************\
  455. * VSURF
  456. *
  457. * View the contents of a surface
  458. *
  459. \**************************************************************************/
  460. DECLARE_API( vsurf )
  461. {
  462. HRESULT hr = S_OK;
  463. BEGIN_API( vsurf );
  464. BOOL BadArg = FALSE;
  465. BOOL AddressIsSURFOBJ = FALSE;
  466. BOOL AddressIsSURFACE = FALSE;
  467. BOOL ArgumentIsHandle = FALSE;
  468. BOOL DisplayToDesktop = FALSE;
  469. PSTR pszMetaFile = NULL;
  470. // Values that can be overridden
  471. DEBUG_VALUE pvScan0 = { 0, DEBUG_VALUE_INVALID};
  472. DEBUG_VALUE lDelta = { 0, DEBUG_VALUE_INVALID};
  473. DEBUG_VALUE iBitmapFormat = { -1, DEBUG_VALUE_INVALID};
  474. DEBUG_VALUE pPal = { 0, DEBUG_VALUE_INVALID};
  475. // Dimension specifications
  476. enum {
  477. left = 0,
  478. top = 1,
  479. cx = 2,
  480. cy = 3,
  481. right = 2,
  482. bottom = 3,
  483. };
  484. BOOL GotAllDims = FALSE;
  485. ULONG DimsFound = 0;
  486. BOOL DimsSpecWxH = FALSE;
  487. DEBUG_VALUE dim[4];
  488. // The address or handle
  489. DEBUG_VALUE SurfSpec = { 0, DEBUG_VALUE_INVALID};
  490. ULONG Rem;
  491. OutputControl OutCtl(Client);
  492. if (Client == NULL)
  493. {
  494. return E_INVALIDARG;
  495. }
  496. while (!BadArg && hr == S_OK)
  497. {
  498. while (isspace(*args)) args++;
  499. if (*args == '-')
  500. {
  501. // Dimensions must be adjacent - raise error later otherwise
  502. if (DimsFound)
  503. {
  504. GotAllDims = TRUE;
  505. }
  506. // Process switches
  507. args++;
  508. BadArg = (*args == '\0' || isspace(*args));
  509. while (*args != '\0' && !isspace(*args))
  510. {
  511. switch (tolower(*args))
  512. {
  513. case 'a':
  514. if (ArgumentIsHandle || AddressIsSURFOBJ)
  515. {
  516. OutCtl.OutErr("Error: Only one of -a, -h, or -o may be specified.\n");
  517. BadArg = TRUE;
  518. }
  519. else
  520. {
  521. AddressIsSURFACE = TRUE;
  522. args++;
  523. }
  524. break;
  525. case 'b':
  526. {
  527. args++;
  528. if (Evaluate(Client, args, DEBUG_VALUE_INT64,
  529. EVALUATE_DEFAULT_RADIX, &pvScan0,
  530. &Rem, NULL,
  531. EVALUATE_COMPACT_EXPR) == S_OK)
  532. {
  533. args += Rem;
  534. }
  535. else
  536. {
  537. OutCtl.OutErr("Error: Couldn't evaluate pvScan0 value from '%s'.\n",
  538. args);
  539. BadArg = TRUE;
  540. }
  541. if (!BadArg &&
  542. Evaluate(Client, args, DEBUG_VALUE_INT64,
  543. EVALUATE_DEFAULT_RADIX, &lDelta,
  544. &Rem, NULL,
  545. EVALUATE_COMPACT_EXPR) == S_OK)
  546. {
  547. args += Rem;
  548. }
  549. else
  550. {
  551. OutCtl.OutErr("Error: Couldn't evaluate lDelta value from '%s'.\n",
  552. args);
  553. BadArg = TRUE;
  554. }
  555. }
  556. break;
  557. case 'd':
  558. DisplayToDesktop = TRUE;
  559. args++;
  560. break;
  561. case 'e':
  562. {
  563. PCSTR pszStart;
  564. SIZE_T FileNameLen;
  565. // Find beginning of path
  566. do
  567. {
  568. args++;
  569. } while (isspace(*args));
  570. pszStart = args;
  571. if (*pszStart == '\0')
  572. {
  573. OutCtl.OutErr("Error: Missing EMF filepath.\n");
  574. BadArg = TRUE;
  575. }
  576. else
  577. {
  578. // Point args beyond path
  579. while (*args != '\0' && !isspace(*args))
  580. {
  581. args++;
  582. }
  583. FileNameLen = args - pszStart;
  584. pszMetaFile = (PSTR) HeapAlloc(GetProcessHeap(), 0, FileNameLen+4+1);
  585. if (pszMetaFile != NULL)
  586. {
  587. RtlCopyMemory(pszMetaFile, pszStart, FileNameLen);
  588. pszMetaFile[FileNameLen] = 0;
  589. // Append .emf if needed
  590. if (FileNameLen < 4 ||
  591. _strnicmp(&pszMetaFile[FileNameLen-4], ".emf", 4) != 0)
  592. {
  593. strcat(pszMetaFile, ".emf");
  594. }
  595. }
  596. else
  597. {
  598. OutCtl.OutErr("Failed to allocate memory.\n");
  599. hr = E_OUTOFMEMORY;
  600. }
  601. }
  602. }
  603. break;
  604. case 'f':
  605. {
  606. do
  607. {
  608. args++;
  609. } while (isspace(*args));
  610. if (_strnicmp(args, "BMF_", sizeof("BMF_")) == 0)
  611. {
  612. ENUMDEF *ped = aedBMF;
  613. SIZE_T CheckLen;
  614. for (ped = aedBMF; ped->psz != NULL; ped++)
  615. {
  616. CheckLen = strlen(ped->psz);
  617. if (_strnicmp(args, ped->psz, CheckLen) == 0 &&
  618. !iscsym(args[CheckLen]))
  619. {
  620. iBitmapFormat.I64 = ped->ul;
  621. iBitmapFormat.Type = DEBUG_VALUE_INT64;
  622. break;
  623. }
  624. }
  625. if (iBitmapFormat.Type != DEBUG_VALUE_INT64)
  626. {
  627. BadArg = TRUE;
  628. }
  629. }
  630. else if (Evaluate(Client, args, DEBUG_VALUE_INT64,
  631. EVALUATE_DEFAULT_RADIX, &iBitmapFormat,
  632. &Rem, NULL,
  633. EVALUATE_COMPACT_EXPR) == S_OK)
  634. {
  635. args += Rem;
  636. }
  637. else
  638. {
  639. BadArg = TRUE;
  640. }
  641. if (BadArg)
  642. {
  643. OutCtl.OutErr("Error: Couldn't evaluate iBitmapFormat value from '%s'.\n",
  644. args);
  645. }
  646. }
  647. break;
  648. case 'h':
  649. if (AddressIsSURFACE || AddressIsSURFOBJ)
  650. {
  651. OutCtl.OutErr("Error: Only one of -a, -h, or -o may be specified.\n");
  652. BadArg = TRUE;
  653. }
  654. else
  655. {
  656. ArgumentIsHandle = TRUE;
  657. args++;
  658. }
  659. break;
  660. case 'o':
  661. if (ArgumentIsHandle || AddressIsSURFACE)
  662. {
  663. OutCtl.OutErr("Error: Only one of -a, -h, or -o may be specified.\n");
  664. BadArg = TRUE;
  665. }
  666. else
  667. {
  668. AddressIsSURFOBJ = TRUE;
  669. args++;
  670. }
  671. break;
  672. case 'p':
  673. {
  674. args++;
  675. if (Evaluate(Client, args, DEBUG_VALUE_INT64,
  676. EVALUATE_DEFAULT_RADIX, &pPal,
  677. &Rem, NULL,
  678. EVALUATE_COMPACT_EXPR) == S_OK)
  679. {
  680. args += Rem;
  681. }
  682. else
  683. {
  684. OutCtl.OutErr("Error: Couldn't evaluate PALETTE address from '%s'.\n",
  685. args);
  686. BadArg = TRUE;
  687. }
  688. }
  689. break;
  690. default:
  691. BadArg = TRUE;
  692. break;
  693. }
  694. if (BadArg) break;
  695. }
  696. }
  697. else
  698. {
  699. if (*args == '\0') break;
  700. if (SurfSpec.Type == DEBUG_VALUE_INVALID)
  701. {
  702. // This argument must be an address or handle.
  703. if (Evaluate(Client, args, DEBUG_VALUE_INT64,
  704. EVALUATE_DEFAULT_RADIX, &SurfSpec,
  705. &Rem, NULL, EVALUATE_COMPACT_EXPR) == S_OK)
  706. {
  707. args += Rem;
  708. }
  709. else
  710. {
  711. OutCtl.OutErr("Error: Couldn't evaluate %s from '%s'.\n",
  712. (AddressIsSURFOBJ ?
  713. "SURFOBJ address" :
  714. "address or handle"),
  715. args);
  716. BadArg = TRUE;
  717. }
  718. }
  719. else if (!GotAllDims)
  720. {
  721. // This argument must be part of dimension specification.
  722. // Check for 'x' indicating WxH specification
  723. if (tolower(args[0]) == 'x' && (args[1] == '\0' || isspace(args[1])))
  724. {
  725. if (DimsFound == 3)
  726. {
  727. args += 2;
  728. DimsSpecWxH = TRUE;
  729. }
  730. else
  731. {
  732. OutCtl.OutErr("Error: Malformed dimension specification.\n");
  733. BadArg = TRUE;
  734. break;
  735. }
  736. }
  737. else
  738. {
  739. if (Evaluate(Client, args, DEBUG_VALUE_INT32,
  740. EVALUATE_DEFAULT_RADIX, &dim[DimsFound],
  741. &Rem, NULL, EVALUATE_COMPACT_EXPR) == S_OK)
  742. {
  743. args += Rem;
  744. DimsFound++;
  745. GotAllDims = (DimsFound == 4);
  746. }
  747. else
  748. {
  749. OutCtl.OutErr("Error: Couldn't evaluate dimension from '%s'.\n",
  750. args);
  751. BadArg = TRUE;
  752. }
  753. }
  754. }
  755. else
  756. {
  757. OutCtl.OutErr("Error: Unexpected argument at '%s'.\n", args);
  758. BadArg = TRUE;
  759. break;
  760. }
  761. }
  762. }
  763. if (hr == S_OK)
  764. {
  765. if (!BadArg)
  766. {
  767. if (DimsFound == 1 || DimsFound == 3)
  768. {
  769. OutCtl.OutErr("Error: Missing part of dimensions.\n");
  770. BadArg = TRUE;
  771. }
  772. else if (SurfSpec.Type == DEBUG_VALUE_INVALID)
  773. {
  774. OutCtl.OutErr("Error: Missing address or handle.\n");
  775. BadArg = TRUE;
  776. }
  777. else if (SurfSpec.I64 == 0)
  778. {
  779. OutCtl.OutErr("Error: Invalid (0) address or handle.\n");
  780. BadArg = TRUE;
  781. }
  782. else if (!DimsSpecWxH && DimsFound == 4)
  783. {
  784. dim[cx].I32 = dim[right].I32 - dim[left].I32;
  785. dim[cy].I32 = dim[bottom].I32 - dim[top].I32;
  786. if ((LONG)dim[cx].I32 < 0 ||
  787. (LONG)dim[cy].I32 < 0)
  788. {
  789. OutCtl.OutErr("Error: Invalid dimensions.\n");
  790. BadArg = TRUE;
  791. }
  792. }
  793. }
  794. if (BadArg)
  795. {
  796. if (*args == '?') OutCtl.Output("View (or save) the contents of a surface\n");
  797. OutCtl.Output("\n"
  798. "Usage: vsurf [-?bdefp] < [-h] HSURF | [-a] SURFACE Addr | -o SURFOBJ Addr> [Dimensions]\n"
  799. " b <pvScan0> <lDelta> - Override those fields from surface\n"
  800. " Zero values will not override\n"
  801. " d - Blt contents to (0,0) on the desktop\n"
  802. " e <Filepath> - Full path to save surface as an EMF\n"
  803. " f <iBitmapFormat> - Overrides bitmap format\n"
  804. " p <PALETTE Addr> - Specifies PALETTE to use for indexed surfaces\n"
  805. " Dimensions = Left Top [Right Bottom | Width x Height]\n"
  806. "\n"
  807. " Notes:\n"
  808. " HBITMAP is the same as HSURF.\n"
  809. " When not saving to a file, a window will be opened.\n"
  810. " -> Use GDIView.exe if debugging remotely.\n");
  811. }
  812. else
  813. {
  814. PDEBUG_SYMBOLS Symbols = NULL;
  815. PDEBUG_DATA_SPACES Data = NULL;
  816. ULONG64 SurfAddr;
  817. if ((hr = Client->QueryInterface(__uuidof(IDebugSymbols),
  818. (void **)&Symbols)) != S_OK ||
  819. (hr = Client->QueryInterface(__uuidof(IDebugDataSpaces),
  820. (void **)&Data)) != S_OK)
  821. {
  822. OutCtl.OutErr("Error setting up debugger interface.\n");
  823. }
  824. else
  825. {
  826. if (AddressIsSURFOBJ)
  827. {
  828. ULONG64 SurfModule = 0;
  829. ULONG SurfTypeId = 0;
  830. ULONG SurfObjOffset;
  831. ULONG BaseObjTypeId = 0;
  832. // Try to read SURFOBJ offset from SURFACE type, but
  833. // if that fails assume it is directly after BASEOBJECT.
  834. if ((hr = GetTypeId(Client, "SURFACE", &SurfTypeId, &SurfModule)) != S_OK ||
  835. (hr = Symbols->GetFieldOffset(SurfModule, SurfTypeId, "so", &SurfObjOffset)) != S_OK)
  836. {
  837. if ((hr = Symbols->GetTypeId(Type_Module.Base, "_BASEOBJECT", &BaseObjTypeId)) == S_OK)
  838. {
  839. hr = Symbols->GetTypeSize(Type_Module.Base, BaseObjTypeId, &SurfObjOffset);
  840. }
  841. }
  842. if (hr != S_OK)
  843. {
  844. OutCtl.OutErr("Error: SURFOBJ to SURFACE lookup failed.\n");
  845. }
  846. else
  847. {
  848. SurfAddr = SurfSpec.I64 - SurfObjOffset;
  849. }
  850. }
  851. else if (AddressIsSURFACE)
  852. {
  853. SurfAddr = SurfSpec.I64;
  854. }
  855. else
  856. {
  857. hr = GetObjectAddress(Client, SurfSpec.I64, &SurfAddr, SURF_TYPE, TRUE, TRUE);
  858. if (hr != S_OK)
  859. {
  860. if (ArgumentIsHandle)
  861. {
  862. OutCtl.OutErr(" 0x%p is not a valid HSURF\n", SurfSpec.I64);
  863. }
  864. else
  865. {
  866. SurfAddr = SurfSpec.I64;
  867. hr = S_OK;
  868. }
  869. }
  870. else
  871. {
  872. ArgumentIsHandle = TRUE;
  873. }
  874. }
  875. }
  876. if (hr == S_OK)
  877. {
  878. enum {
  879. SF_hHmgr,
  880. //SF_ulShareCount,
  881. //SF_cExclusiveLock,
  882. //SF_Tid,
  883. SF_so_dhsurf,
  884. SF_so_hsurf,
  885. SF_so_dhpdev,
  886. SF_so_hdev,
  887. SF_so_sizlBitmap_cx,
  888. SF_so_sizlBitmap_cy,
  889. SF_so_cjBits,
  890. SF_so_pvBits,
  891. SF_so_pvScan0,
  892. SF_so_lDelta,
  893. SF_so_iUniq,
  894. SF_so_iBitmapFormat,
  895. SF_so_iType,
  896. SF_so_fjBitmap,
  897. //SF_pdcoAA,
  898. //SF_SurfFlags,
  899. SF_pPal,
  900. //SF_EBitmap_hdc,
  901. //SF_EBitmap_cRef,
  902. //SF_EBitmap_hpalHint,
  903. //SF_EBitmap_sizlDim_cx,
  904. //SF_EBitmap_sizlDim_cy,
  905. SF_TOTAL
  906. };
  907. DEBUG_VALUE SurfValues[SF_TOTAL];
  908. DEBUG_VALUE ObjHandle;
  909. TypeOutputParser SurfParser(Client); // SURFACE dump
  910. OutputFilter OutFilter(Client); // For other misc types
  911. OutputState OutState(Client);
  912. OutputControl OutCtlToFilter;
  913. ULONG64 SurfAddrFromHmgr;
  914. CHAR szFallbackDTCmd[128];
  915. struct {
  916. BITMAPINFOHEADER bmiHeader;
  917. DWORD bmiColors[256];
  918. } bmi;
  919. for (int svi = 0; svi < SF_TOTAL; svi++)
  920. {
  921. SurfValues[svi].Type = DEBUG_VALUE_INVALID;
  922. }
  923. if ((hr = OutState.Setup(0, &SurfParser)) != S_OK ||
  924. ((hr = OutState.OutputTypeVirtual(SurfAddr,
  925. "SURFACE",
  926. DEBUG_OUTTYPE_BLOCK_RECURSE)) != S_OK &&
  927. ((sprintf(szFallbackDTCmd,
  928. "dt " GDIType(SURFACE) " hHmgr -y so. -y so.sizlBitmap. pPal 0x%I64x",
  929. SurfAddr) == 0) ||
  930. (hr = OutState.Execute(szFallbackDTCmd)) != S_OK)) ||
  931. (hr = SurfParser.Get(&SurfValues[SF_hHmgr],
  932. "hHmgr",
  933. DEBUG_VALUE_INT64)) != S_OK)
  934. {
  935. OutCtl.OutErr("Unable to get contents of SURFACE::hHmgr\n");
  936. OutCtl.OutErr(" (Type Read returned %s)\n", pszHRESULT(hr));
  937. if (AddressIsSURFOBJ)
  938. {
  939. OutCtl.OutErr(" 0x%p is not a valid SURFOBJ address\n", SurfSpec.I64);
  940. }
  941. else if (AddressIsSURFACE)
  942. {
  943. OutCtl.OutErr(" 0x%p is not a valid SURFACE address\n", SurfSpec.I64);
  944. }
  945. else if (ArgumentIsHandle)
  946. {
  947. OutCtl.OutErr(" although 0x%p is a valid HSURF\n", SurfSpec.I64);
  948. }
  949. else
  950. {
  951. OutCtl.OutErr(" 0x%p is neither an HSURF nor valid SURFACE address\n", SurfSpec.I64);
  952. }
  953. }
  954. else if ((hr = OutState.Setup(0, &OutFilter)) != S_OK ||
  955. (hr = OutCtlToFilter.SetControl(DEBUG_OUTCTL_THIS_CLIENT |
  956. DEBUG_OUTCTL_NOT_LOGGED |
  957. DEBUG_OUTCTL_OVERRIDE_MASK,
  958. OutState.Client)) != S_OK)
  959. {
  960. OutCtl.OutErr("Error preparing misc type reader.\n");
  961. }
  962. else
  963. {
  964. if (!ArgumentIsHandle)
  965. {
  966. if (GetObjectAddress(Client, SurfValues[SF_hHmgr].I64, &SurfAddrFromHmgr,
  967. SURF_TYPE, TRUE, FALSE) == S_OK &&
  968. SurfAddrFromHmgr != SurfAddr)
  969. {
  970. OutCtl.OutWarn("\tNote: SURFACE may not be valid.\n"
  971. "\t It does not have a valid handle manager entry.\n");
  972. }
  973. }
  974. if (SurfParser.Get(&SurfValues[SF_so_hsurf], "hsurf", DEBUG_VALUE_INT64) != S_OK)
  975. {
  976. OutCtl.OutWarn("Warning: Couldn't read hsurf.\n");
  977. }
  978. else
  979. {
  980. if (SurfValues[SF_so_hsurf].I64 != SurfValues[SF_hHmgr].I64)
  981. {
  982. OutCtl.OutWarn("Warning: hsurf, 0x%p, != hHmgr, 0x%p.\n",
  983. SurfValues[SF_so_hsurf].I64,
  984. SurfValues[SF_hHmgr].I64);
  985. }
  986. }
  987. // Check dimensions
  988. if (DimsFound < 2)
  989. {
  990. dim[left].I32 = 0;
  991. dim[top].I32 = 0;
  992. }
  993. if ((hr = SurfParser.Get(&SurfValues[SF_so_sizlBitmap_cx], "cx", DEBUG_VALUE_INT32)) != S_OK ||
  994. (hr = SurfParser.Get(&SurfValues[SF_so_sizlBitmap_cy], "cy", DEBUG_VALUE_INT32)) != S_OK)
  995. {
  996. if (DimsFound == 4 && dim[cx].Type == DEBUG_VALUE_INT32 && dim[cy].Type == DEBUG_VALUE_INT32)
  997. {
  998. hr = S_OK;
  999. bmi.bmiHeader.biWidth = dim[cx].I32;
  1000. bmi.bmiHeader.biHeight = dim[cy].I32;
  1001. }
  1002. else
  1003. {
  1004. OutCtl.OutErr("Error: Couldn't get SURFACE dimensions.\n");
  1005. }
  1006. }
  1007. else
  1008. {
  1009. bmi.bmiHeader.biWidth = SurfValues[SF_so_sizlBitmap_cx].I32;
  1010. bmi.bmiHeader.biHeight = SurfValues[SF_so_sizlBitmap_cy].I32;
  1011. bmi.bmiHeader.biWidth -= dim[left].I32;
  1012. bmi.bmiHeader.biHeight -= dim[top].I32;
  1013. if (DimsFound == 4)
  1014. {
  1015. if ((LONG)dim[cx].I32 < bmi.bmiHeader.biWidth)
  1016. {
  1017. bmi.bmiHeader.biWidth = (LONG)dim[cx].I32;
  1018. }
  1019. if ((LONG)dim[cy].I32 < bmi.bmiHeader.biHeight)
  1020. {
  1021. bmi.bmiHeader.biHeight = (LONG)dim[cy].I32;
  1022. }
  1023. }
  1024. }
  1025. if (hr == S_OK)
  1026. {
  1027. if (bmi.bmiHeader.biWidth <= 0)
  1028. {
  1029. OutCtl.OutWarn("Error: Invalid x dimensions.\n");
  1030. hr = S_FALSE;
  1031. }
  1032. else if (bmi.bmiHeader.biHeight <= 0)
  1033. {
  1034. OutCtl.OutWarn("Error: Invalid y dimensions.\n");
  1035. hr = S_FALSE;
  1036. }
  1037. }
  1038. // Check pvScan0
  1039. if (hr == S_OK)
  1040. {
  1041. if ((hr = SurfParser.Get(&SurfValues[SF_so_pvScan0], "pvScan0", DEBUG_VALUE_INT64)) != S_OK)
  1042. {
  1043. if (pvScan0.Type == DEBUG_VALUE_INT64 && pvScan0.I64 != 0)
  1044. {
  1045. hr = S_OK;
  1046. }
  1047. else
  1048. {
  1049. OutCtl.OutErr("Error: Couldn't get address of first scanline.\n");
  1050. if (SurfParser.Get(&SurfValues[SF_so_dhsurf], "dhsurf", DEBUG_VALUE_INT64) == S_OK)
  1051. {
  1052. OutCtl.Output(" dhsurf is 0x%p.\n", SurfValues[SF_so_dhsurf].I64);
  1053. }
  1054. }
  1055. }
  1056. else if (SurfValues[SF_so_pvScan0].I64 == 0 &&
  1057. pvScan0.Type == DEBUG_VALUE_INT64 &&
  1058. pvScan0.I64 != 0)
  1059. {
  1060. OutCtl.OutWarn(" Overriding pvScan0, 0x%p, with 0x%p.\n",
  1061. SurfValues[SF_so_pvScan0].I64,
  1062. pvScan0.I64);
  1063. }
  1064. else
  1065. {
  1066. pvScan0 = SurfValues[SF_so_pvScan0];
  1067. }
  1068. }
  1069. // Check lDelta
  1070. if (hr == S_OK)
  1071. {
  1072. if ((hr = SurfParser.Get(&SurfValues[SF_so_lDelta], "lDelta", DEBUG_VALUE_INT64)) != S_OK)
  1073. {
  1074. if (lDelta.Type == DEBUG_VALUE_INT64 && lDelta.I64 != 0)
  1075. {
  1076. hr = S_OK;
  1077. }
  1078. else
  1079. {
  1080. OutCtl.OutErr("Error: Couldn't get SURFACE lDelta.\n");
  1081. if (SurfParser.Get(&SurfValues[SF_so_dhsurf], "dhsurf", DEBUG_VALUE_INT64) == S_OK)
  1082. {
  1083. OutCtl.Output(" dhsurf is 0x%p.\n", SurfValues[SF_so_dhsurf].I64);
  1084. }
  1085. }
  1086. }
  1087. else if (SurfValues[SF_so_lDelta].I64 == 0 &&
  1088. lDelta.Type == DEBUG_VALUE_INT64 &&
  1089. lDelta.I64 != 0)
  1090. {
  1091. OutCtl.OutWarn(" Overriding lDelta, 0x%p, with 0x%p.\n",
  1092. SurfValues[SF_so_lDelta].I64,
  1093. lDelta.I64);
  1094. }
  1095. else
  1096. {
  1097. lDelta = SurfValues[SF_so_lDelta];
  1098. }
  1099. }
  1100. // Check iBitmapFormat
  1101. if (hr == S_OK)
  1102. {
  1103. if ((hr = SurfParser.Get(&SurfValues[SF_so_iBitmapFormat], "iBitmapFormat", DEBUG_VALUE_INT64)) != S_OK)
  1104. {
  1105. if (iBitmapFormat.Type == DEBUG_VALUE_INT64 && iBitmapFormat.I64 != 0)
  1106. {
  1107. hr = S_OK;
  1108. }
  1109. else
  1110. {
  1111. OutCtl.OutErr("Error: Couldn't get SURFACE iBitmapFormat.\n");
  1112. }
  1113. }
  1114. else if (SurfValues[SF_so_iBitmapFormat].I64 == 0 &&
  1115. iBitmapFormat.Type == DEBUG_VALUE_INT64 &&
  1116. iBitmapFormat.I64 != 0)
  1117. {
  1118. OutCtl.OutWarn(" Overriding iBitmapFormat, 0x%p, with 0x%p.\n",
  1119. SurfValues[SF_so_iBitmapFormat].I64,
  1120. iBitmapFormat.I64);
  1121. }
  1122. else
  1123. {
  1124. iBitmapFormat = SurfValues[SF_so_iBitmapFormat];
  1125. }
  1126. }
  1127. if (hr == S_OK)
  1128. {
  1129. bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
  1130. bmi.bmiHeader.biPlanes = 1;
  1131. bmi.bmiHeader.biCompression = BI_RGB;
  1132. bmi.bmiHeader.biSizeImage = 0;
  1133. bmi.bmiHeader.biXPelsPerMeter = bmi.bmiHeader.biYPelsPerMeter = 0;
  1134. bmi.bmiHeader.biClrUsed = 0;
  1135. bmi.bmiHeader.biClrImportant = 0;
  1136. if (SurfValues[SF_so_iBitmapFormat].I32 == BMF_32BPP)
  1137. {
  1138. bmi.bmiHeader.biBitCount = 32;
  1139. }
  1140. else if (SurfValues[SF_so_iBitmapFormat].I32 == BMF_24BPP)
  1141. {
  1142. bmi.bmiHeader.biBitCount = 24;
  1143. }
  1144. else
  1145. {
  1146. if (SurfValues[SF_so_iBitmapFormat].I32 == BMF_16BPP)
  1147. {
  1148. bmi.bmiHeader.biBitCount = 16;
  1149. }
  1150. else if (SurfValues[SF_so_iBitmapFormat].I32 == BMF_8BPP)
  1151. {
  1152. bmi.bmiHeader.biBitCount = 8;
  1153. }
  1154. else if (SurfValues[SF_so_iBitmapFormat].I32 == BMF_4BPP)
  1155. {
  1156. bmi.bmiHeader.biBitCount = 4;
  1157. }
  1158. else if (SurfValues[SF_so_iBitmapFormat].I32 == BMF_1BPP)
  1159. {
  1160. bmi.bmiHeader.biBitCount = 1;
  1161. }
  1162. else
  1163. {
  1164. OutCtl.OutErr("Unrecognized iBitmapFormat %ld.\n", SurfValues[SF_so_iBitmapFormat].I32);
  1165. hr = S_FALSE;
  1166. }
  1167. }
  1168. }
  1169. if (hr == S_OK && bmi.bmiHeader.biBitCount < 24)
  1170. {
  1171. // Get PALETTE
  1172. if (SurfParser.Get(&SurfValues[SF_pPal], "pPal", DEBUG_VALUE_INT64) == S_OK)
  1173. {
  1174. if (pPal.Type == DEBUG_VALUE_INT64)
  1175. {
  1176. if (SurfValues[SF_pPal].I64 != 0 &&
  1177. pPal.I64 != SurfValues[SF_pPal].I64)
  1178. {
  1179. OutCtl.OutWarn(" Overriding PALETTE address, 0x%p, with 0x%p.\n",
  1180. SurfValues[SF_pPal].I64,
  1181. pPal.I64);
  1182. }
  1183. }
  1184. else
  1185. {
  1186. pPal = SurfValues[SF_pPal];
  1187. }
  1188. }
  1189. else if (pPal.Type != DEBUG_VALUE_INT64)
  1190. {
  1191. OutCtl.OutWarn(" Error reading PALETTE address from SURFACE.\n");
  1192. }
  1193. // Try getting the PALETTE from the PDEV if need be
  1194. if (pPal.Type != DEBUG_VALUE_INT64 || pPal.I64 == 0)
  1195. {
  1196. if ((hr = SurfParser.Get(&SurfValues[SF_so_hdev], "hdev", DEBUG_VALUE_INT64)) == S_OK &&
  1197. SurfValues[SF_so_hdev].I64 != 0)
  1198. {
  1199. OutFilter.DiscardOutput();
  1200. if ((hr = OutState.OutputTypeVirtual(SurfValues[SF_so_hdev].I64, "PDEV", 0)) != S_OK ||
  1201. (hr = OutFilter.Query("ppalSurf", &pPal, DEBUG_VALUE_INT64)) != S_OK)
  1202. {
  1203. OutCtl.OutErr(" Error reading PALETTE address from PDEV.\n");
  1204. pPal.Type = DEBUG_VALUE_INVALID;
  1205. }
  1206. }
  1207. }
  1208. // Read PALETTE settings
  1209. if (pPal.Type == DEBUG_VALUE_INT64 && pPal.I64 != 0)
  1210. {
  1211. PCSTR ReqPALETTEFields[] = {
  1212. "flPal",
  1213. "cEntries",
  1214. "apalColor",
  1215. NULL
  1216. };
  1217. TypeOutputDumper PALReader(OutState.Client, &OutCtlToFilter);
  1218. DEBUG_VALUE cEntries;
  1219. DEBUG_VALUE ppalColor;
  1220. BOOL Check565 = FALSE;
  1221. BOOL Check555 = FALSE;
  1222. PALReader.IncludeMarked();
  1223. PALReader.MarkFields(ReqPALETTEFields);
  1224. OutFilter.DiscardOutput();
  1225. if ((hr = PALReader.OutputVirtual("PALETTE", pPal.I64)) == S_OK &&
  1226. (hr = OutFilter.Query("cEntries", &cEntries, DEBUG_VALUE_INT32)) == S_OK)
  1227. {
  1228. bmi.bmiHeader.biClrUsed = cEntries.I32;
  1229. if ((hr = OutFilter.Query("PAL_FIXED")) != S_OK &&
  1230. (hr = OutFilter.Query("PAL_INDEXED")) != S_OK)
  1231. {
  1232. OutCtl.OutErr(" Error: vsurf only supports fixed and indexed palettes.\n");
  1233. }
  1234. else if (OutFilter.Query("PAL_BITFIELDS") == S_OK)
  1235. {
  1236. if (bmi.bmiHeader.biClrUsed > 0)
  1237. {
  1238. OutCtl.OutErr(" Error: PALETTE @ 0x%p is BITFIELDS, but has Entries.\n", pPal.I64);
  1239. hr = S_FALSE;
  1240. }
  1241. else
  1242. {
  1243. bmi.bmiHeader.biCompression = BI_BITFIELDS;
  1244. bmi.bmiHeader.biClrUsed = 3;
  1245. if (OutFilter.Query("PAL_RGB16_565") == S_OK)
  1246. {
  1247. Check565 = TRUE;
  1248. }
  1249. else if (OutFilter.Query("PAL_RGB16_555") == S_OK)
  1250. {
  1251. Check555 = TRUE;
  1252. }
  1253. else
  1254. {
  1255. OutCtl.OutWarn(" Warning: Nonstandard bitfields format in PALETTE @ 0x%p.\n",
  1256. pPal.I64);
  1257. }
  1258. }
  1259. }
  1260. if (hr == S_OK && bmi.bmiHeader.biClrUsed > 0)
  1261. {
  1262. if (bmi.bmiHeader.biClrUsed > 256 ||
  1263. OutFilter.Query("apalColor", &ppalColor, DEBUG_VALUE_INT64) != S_OK ||
  1264. ppalColor.I64 == 0)
  1265. {
  1266. OutCtl.OutErr(" Error: PALETTE @ 0x%p is invalid.\n", pPal.I64);
  1267. hr = S_FALSE;
  1268. }
  1269. else
  1270. {
  1271. ULONG PALBytes = bmi.bmiHeader.biClrUsed * sizeof(DWORD);
  1272. ULONG BytesRead;
  1273. OutCtl.OutVerb("Reading %ld palette entries @ 0x%p.\n",
  1274. bmi.bmiHeader.biClrUsed, ppalColor.I64);
  1275. hr = Data->ReadVirtual(ppalColor.I64, bmi.bmiColors, PALBytes, &BytesRead);
  1276. if (hr != S_OK)
  1277. {
  1278. OutCtl.OutErr("Error: Couldn't read any PALETTE entries at 0x%p.\n", ppalColor.I64);
  1279. }
  1280. else if (BytesRead != PALBytes)
  1281. {
  1282. OutCtl.OutErr("Error: Only read %lu of %lu bytes from PALETTE entries at 0x%p.\n",
  1283. BytesRead,
  1284. PALBytes,
  1285. ppalColor.I64);
  1286. hr = S_FALSE;
  1287. }
  1288. else
  1289. {
  1290. if (Check565)
  1291. {
  1292. if (bmi.bmiColors[0] != 0xf800 ||
  1293. bmi.bmiColors[1] != 0x07e0 ||
  1294. bmi.bmiColors[2] != 0x001f)
  1295. {
  1296. OutCtl.OutWarn(" Palette bitfields don't match standard 565 format.\n");
  1297. }
  1298. }
  1299. else if (Check555)
  1300. {
  1301. if (bmi.bmiColors[0] != 0x7c00 ||
  1302. bmi.bmiColors[1] != 0x03e0 ||
  1303. bmi.bmiColors[2] != 0x001f)
  1304. {
  1305. OutCtl.OutWarn(" Palette bitfields don't match standard 555 format.\n");
  1306. }
  1307. }
  1308. }
  1309. }
  1310. }
  1311. }
  1312. else
  1313. {
  1314. OutCtl.OutErr(" Error reading PALETTE.\n");
  1315. }
  1316. }
  1317. else
  1318. {
  1319. OutCtl.OutErr("Error: Unable to obtain valid PALETTE address.\n");
  1320. if (hr == S_OK) hr = S_FALSE;
  1321. }
  1322. }
  1323. if (hr == S_OK)
  1324. {
  1325. // We have all the format information we need from the target.
  1326. ULONG FirstBit = dim[left].I32*bmi.bmiHeader.biBitCount;
  1327. LONG xOrigin;
  1328. LONG Width;
  1329. HBITMAP hBitmap;
  1330. LPVOID pDIBits;
  1331. if (SurfParser.Get(&SurfValues[SF_so_iUniq], "iUniq", DEBUG_VALUE_INT32) != S_OK)
  1332. {
  1333. SurfValues[SF_so_iUniq].I32 = 0;
  1334. }
  1335. // Save original width and adjust for full byte reads if needed
  1336. xOrigin = (LONG)(FirstBit & 0x7);
  1337. Width = (LONG)bmi.bmiHeader.biWidth;
  1338. bmi.bmiHeader.biWidth += (FirstBit & 0x7);
  1339. bmi.bmiHeader.biWidth = (bmi.bmiHeader.biWidth + 0x7) & ~0x7;
  1340. // Create a Top-Down DIB Section
  1341. bmi.bmiHeader.biHeight = -bmi.bmiHeader.biHeight;
  1342. hBitmap = CreateDIBSection(NULL, (LPBITMAPINFO)&bmi, DIB_RGB_COLORS, &pDIBits, NULL, 0);
  1343. if (hBitmap)
  1344. {
  1345. DIBSECTION ds;
  1346. if (GetObject(hBitmap, sizeof(ds), &ds) != 0)
  1347. {
  1348. HRESULT hr = S_OK;
  1349. PBYTE pBits = (PBYTE)pDIBits;
  1350. ULONG64 ScanAddr = pvScan0.I64;
  1351. ULONG ScanSize;
  1352. ULONG ScanBytesRead;
  1353. BOOL GoodRead = FALSE;
  1354. LONG LastScanWithData = -1;
  1355. ScanSize = ds.dsBm.bmWidthBytes;
  1356. ScanAddr += FirstBit/8 + dim[top].I32*lDelta.I64;
  1357. for (LONG y = 0; y < ds.dsBm.bmHeight; y++)
  1358. {
  1359. OutCtl.Output(".");
  1360. if (y % 70 == 69) OutCtl.Output("%ld%% read\n", 100*y/ds.dsBm.bmHeight);
  1361. if (OutCtl.GetInterrupt() == S_OK)
  1362. {
  1363. break;
  1364. }
  1365. if ((hr = Data->ReadVirtual(ScanAddr, pBits, ScanSize, &ScanBytesRead)) != S_OK)
  1366. {
  1367. ScanBytesRead = 0;
  1368. hr = S_OK;
  1369. }
  1370. else
  1371. {
  1372. GoodRead = TRUE;
  1373. }
  1374. if (ScanBytesRead != ScanSize)
  1375. {
  1376. if (LastScanWithData+1 == y || ScanBytesRead != 0)
  1377. {
  1378. OutCtl.OutErr("ReadVirtual(0x%p) failed read @ 0x%p (scan %ld).\n", ScanAddr, ScanAddr+ScanBytesRead, y);
  1379. }
  1380. RtlZeroMemory(pBits+ScanBytesRead,ScanSize-ScanBytesRead);
  1381. // If this scan crosses into next page,
  1382. // try reading a partial scan from that page.
  1383. if (ScanBytesRead == 0 && PageSize != 0)
  1384. {
  1385. ULONG64 NextPage;
  1386. ULONG ReadSize;
  1387. for (NextPage = (ScanAddr + PageSize) & ~((ULONG64)PageSize-1);
  1388. NextPage < ScanAddr + ScanSize;
  1389. NextPage += PageSize
  1390. )
  1391. {
  1392. ReadSize = ScanSize - (ULONG)(NextPage - ScanAddr);
  1393. if (Data->ReadVirtual(NextPage, pBits + ScanSize - ReadSize, ReadSize, &ScanBytesRead) == S_OK)
  1394. {
  1395. GoodRead = TRUE;
  1396. if (ScanBytesRead != 0)
  1397. {
  1398. OutCtl.OutErr("Partial scan read of %lu bytes succeeded @ 0x%p (scan %ld).\n", ScanBytesRead, NextPage, y);
  1399. if (ScanBytesRead == ReadSize) break;
  1400. }
  1401. }
  1402. }
  1403. }
  1404. }
  1405. if (ScanBytesRead != 0)
  1406. {
  1407. if (LastScanWithData+1 != y && ScanBytesRead == ScanSize)
  1408. {
  1409. OutCtl.OutErr("Next fully successful ReadVirtual @ 0x%p (scan %ld).\n", ScanAddr, y);
  1410. }
  1411. LastScanWithData = y;
  1412. }
  1413. pBits += ScanSize;
  1414. ScanAddr += lDelta.I64;
  1415. }
  1416. OutCtl.Output("\n");
  1417. if (LastScanWithData + 1 != ds.dsBm.bmHeight)
  1418. {
  1419. OutCtl.OutErr("Scans %ld to %ld weren't read.\n",
  1420. LastScanWithData + 1,
  1421. ds.dsBm.bmHeight - 1);
  1422. }
  1423. SURF_INFO SurfInfo = { {0}, hBitmap,
  1424. xOrigin,
  1425. 0,
  1426. Width,
  1427. ds.dsBm.bmHeight,
  1428. ds.dsBm.bmBitsPixel
  1429. };
  1430. _stprintf(SurfInfo.SurfName,
  1431. "%s @ 0x%I64x (%lu,%lu)-(%lu,%lu) [Uniq=0x%lx]",
  1432. ((AddressIsSURFOBJ) ?
  1433. _T("SURFOBJ") :
  1434. _T("SURFACE")),
  1435. ((AddressIsSURFOBJ) ?
  1436. SurfSpec.I64 :
  1437. SurfAddr),
  1438. dim[left].I32,
  1439. dim[top].I32,
  1440. dim[left].I32 + Width,
  1441. dim[top].I32 + ds.dsBm.bmHeight,
  1442. SurfValues[SF_so_iUniq].I32);
  1443. if (GoodRead)
  1444. {
  1445. OutCtl.OutVerb("%s %s\n",
  1446. ((pszMetaFile != NULL) ?
  1447. "Saving" : "Displaying"),
  1448. SurfInfo.SurfName);
  1449. }
  1450. if (!GoodRead)
  1451. {
  1452. OutCtl.OutErr("No image data was read.\n");
  1453. DeleteObject(hBitmap);
  1454. }
  1455. else if (pszMetaFile != NULL || DisplayToDesktop)
  1456. {
  1457. HDC hdcSurface = CreateCompatibleDC(NULL);
  1458. if (hdcSurface == NULL ||
  1459. SelectObject(hdcSurface, hBitmap) == NULL)
  1460. {
  1461. OutCtl.OutErr("Error: Failed to prepare captured surface for Blt.\n");
  1462. OutCtl.OutVerb(" Last error: 0x%lx.\n", GetLastError());
  1463. }
  1464. else
  1465. {
  1466. if (pszMetaFile != NULL)
  1467. {
  1468. HDC hdcMeta = CreateEnhMetaFile(NULL, pszMetaFile, NULL, SurfInfo.SurfName);
  1469. if (hdcMeta == NULL ||
  1470. !BitBlt(hdcMeta, 0, 0, Width, ds.dsBm.bmHeight,
  1471. hdcSurface, xOrigin, 0, SRCCOPY))
  1472. {
  1473. OutCtl.OutErr("Error: Save to metafile failed.\n");
  1474. OutCtl.OutVerb(" Last error: 0x%lx.\n", GetLastError());
  1475. }
  1476. DeleteEnhMetaFile(CloseEnhMetaFile(hdcMeta));
  1477. }
  1478. if (DisplayToDesktop)
  1479. {
  1480. HDC hdcScreen = GetDC(NULL);
  1481. if (hdcScreen == NULL ||
  1482. !Rectangle(hdcScreen, 0, 0, ds.dsBm.bmWidth+2, ds.dsBm.bmHeight+2) ||
  1483. !BitBlt(hdcScreen, 1, 1, Width, ds.dsBm.bmHeight,
  1484. hdcSurface, xOrigin, 0, SRCCOPY))
  1485. {
  1486. OutCtl.OutErr("Error: Display to screen failed.\n");
  1487. OutCtl.OutVerb(" Last error: 0x%lx.\n", GetLastError());
  1488. }
  1489. ReleaseDC(NULL, hdcScreen);
  1490. }
  1491. }
  1492. DeleteObject(hBitmap);
  1493. DeleteDC(hdcSurface);
  1494. }
  1495. else if (CreateViewer(Client, &SurfInfo) == 0)
  1496. {
  1497. OutCtl.OutErr("CreateViewer failed.\n");
  1498. DbgPrint("CreateViewer failed.\n");
  1499. DeleteObject(hBitmap);
  1500. }
  1501. }
  1502. else
  1503. {
  1504. OutCtl.OutErr("GetDIBits failed.\n");
  1505. DeleteObject(hBitmap);
  1506. }
  1507. }
  1508. else
  1509. {
  1510. OutCtl.OutErr("CreateDIBSection failed.\n");
  1511. OutCtl.OutVerb(" GetLastError: 0x%lx.\n", GetLastError());
  1512. }
  1513. }
  1514. else
  1515. {
  1516. OutCtl.OutErr("Error: Couldn't read required SURFACE fields.\n");
  1517. }
  1518. }
  1519. }
  1520. if (Data != NULL) Data->Release();
  1521. if (Symbols != NULL) Symbols->Release();
  1522. }
  1523. }
  1524. if (pszMetaFile != NULL)
  1525. {
  1526. HeapFree(GetProcessHeap(), 0, pszMetaFile);
  1527. }
  1528. return hr;
  1529. }
  1530. LONG
  1531. DebuggerExceptionFilter(
  1532. struct _EXCEPTION_POINTERS *ExceptionInfo,
  1533. PDEBUG_CLIENT Client,
  1534. PCSTR Interface,
  1535. PCSTR Func
  1536. )
  1537. {
  1538. // Any references to objects will be leaked.
  1539. OutputControl OutCtl(Client);
  1540. CHAR szBuffer[80];
  1541. if (Interface != NULL && Func != NULL)
  1542. {
  1543. OutCtl.OutErr("%08x Exception in debugger %s.%s.\n",
  1544. ExceptionInfo->ExceptionRecord->ExceptionCode,
  1545. Interface,
  1546. Func
  1547. );
  1548. }
  1549. else
  1550. {
  1551. OutCtl.OutErr("%08x Exception in extension %s.\n",
  1552. ExceptionInfo->ExceptionRecord->ExceptionCode,
  1553. Func
  1554. );
  1555. }
  1556. StringCbPrintfA(szBuffer, sizeof(szBuffer),
  1557. " PC: 0x%p ExceptionInformation: 0x%p 0x%p 0x%p\n",
  1558. ExceptionInfo->ExceptionRecord->ExceptionAddress,
  1559. ExceptionInfo->ExceptionRecord->ExceptionInformation[0],
  1560. ExceptionInfo->ExceptionRecord->ExceptionInformation[1],
  1561. ExceptionInfo->ExceptionRecord->ExceptionInformation[2]
  1562. );
  1563. OutCtl.OutErr("%s", szBuffer);
  1564. return EXCEPTION_EXECUTE_HANDLER;
  1565. }
  1566. HRESULT
  1567. AssembleTempRoutine(
  1568. PDEBUG_CLIENT Client,
  1569. Instruction *instructions,
  1570. PCSTR Arguments
  1571. )
  1572. {
  1573. static BOOL CodeWritten = FALSE;
  1574. static PDEBUG_CONTROL2 Control = NULL;
  1575. static PDEBUG_DATA_SPACES Data = NULL;
  1576. static PDEBUG_REGISTERS Registers = NULL;
  1577. static PDEBUG_SYMBOLS Symbols = NULL;
  1578. static ULONG RegisterCount = 0;
  1579. static PDEBUG_VALUE SavedRegisters = NULL;
  1580. static ULONG64 IP = 0;
  1581. static BYTE OldCode[256] = "";
  1582. static ULONG CodeRead = 0;
  1583. static ULONG64 FinalIP = 0;
  1584. HRESULT hr;
  1585. OutputControl OutCtl(Client);
  1586. ULONG CodeRestored;
  1587. if (!CodeWritten && RegisterCount == 0)
  1588. {
  1589. if ((hr = Client->QueryInterface(__uuidof(IDebugControl2),
  1590. (void **)&Control)) == S_OK &&
  1591. (hr = Client->QueryInterface(__uuidof(IDebugDataSpaces),
  1592. (void **)&Data)) == S_OK &&
  1593. (hr = Client->QueryInterface(__uuidof(IDebugRegisters),
  1594. (void **)&Registers)) == S_OK &&
  1595. (hr = Client->QueryInterface(__uuidof(IDebugSymbols),
  1596. (void **)&Symbols)) == S_OK)
  1597. {
  1598. DEBUG_VALUE Argument;
  1599. ULONG Rem;
  1600. ULONG64 LimitIP;
  1601. ULONG64 AsmIP;
  1602. ULONG64 StartIP;
  1603. ULONG64 EndIP;
  1604. ULONG CodeEmitted;
  1605. if (hr == S_OK &&
  1606. (hr = Registers->GetInstructionOffset(&IP)) == S_OK &&
  1607. (hr = Data->ReadVirtual(IP, OldCode, sizeof(OldCode), &CodeRead)) == S_OK &&
  1608. CodeRead == sizeof(OldCode))
  1609. {
  1610. OutCtl.Output("Code from 0x%p to 0x%p saved.\n", IP, IP+CodeRead);
  1611. LimitIP = IP + CodeRead - 0x20; // Enough space for any instruction
  1612. StartIP = EndIP = IP;
  1613. for (int i = 0; hr == S_OK && instructions[i].Code != NULL; i++)
  1614. {
  1615. AsmIP = EndIP;
  1616. if (AsmIP > LimitIP)
  1617. {
  1618. OutCtl.OutErr("\nError: There may not be enough code saved to assemble @ 0x%p.\n"
  1619. "\n Aborting to be on the safe side.",
  1620. AsmIP);
  1621. hr = E_OUTOFMEMORY;
  1622. }
  1623. if (hr == S_OK &&
  1624. instructions[i].Flags & I_WRITE_ADDRESS)
  1625. {
  1626. hr = Evaluate(Client, Arguments,
  1627. DEBUG_VALUE_INT32, EVALUATE_DEFAULT_RADIX,
  1628. &Argument, &Rem, NULL, EVALUATE_COMPACT_EXPR);
  1629. if (hr == S_OK)
  1630. {
  1631. Arguments += Rem;
  1632. }
  1633. else
  1634. {
  1635. OutCtl.OutErr("\nMissing address for instruction %#lu '%s'",
  1636. i,
  1637. (instructions[i].ByteLen == 0) ?
  1638. instructions[i].Code :
  1639. "Emitted Bytes");
  1640. }
  1641. }
  1642. if (hr == S_OK)
  1643. {
  1644. if (instructions[i].Flags & I_START_IP)
  1645. {
  1646. StartIP = AsmIP;
  1647. }
  1648. OutCtl.Output(".");
  1649. if (instructions[i].ByteLen > 0)
  1650. {
  1651. OutCtl.OutVerb(" Emitting %lu bytes @ 0x%p...\n",
  1652. instructions[i].ByteLen, AsmIP);
  1653. hr = Data->WriteVirtual(AsmIP, instructions[i].Code, instructions[i].ByteLen, &CodeEmitted);
  1654. if (hr == S_OK)
  1655. {
  1656. if (CodeEmitted == instructions[i].ByteLen)
  1657. EndIP = AsmIP + CodeEmitted;
  1658. else
  1659. hr = E_FAIL;
  1660. }
  1661. }
  1662. else
  1663. {
  1664. OutCtl.OutVerb(" Assembling '%s' @ 0x%p...\n", instructions[i].Code, AsmIP);
  1665. hr = Control->Assemble(AsmIP, instructions[i].Code, &EndIP);
  1666. }
  1667. }
  1668. if (hr == S_OK)
  1669. {
  1670. if (instructions[i].Flags & I_WRITE_ADDRESS)
  1671. {
  1672. hr = Data->WriteVirtual(EndIP-sizeof(Argument.I32),
  1673. &Argument.I32,
  1674. sizeof(Argument.I32),
  1675. &CodeEmitted);
  1676. if (hr == S_OK)
  1677. {
  1678. if (CodeEmitted != sizeof(Argument.I32))
  1679. {
  1680. hr = E_FAIL;
  1681. }
  1682. else
  1683. {
  1684. OutCtl.OutVerb(" Wrote argument 0x%lx at 0x%p.\n",
  1685. Argument.I32,
  1686. EndIP - sizeof(Argument.I32));
  1687. }
  1688. }
  1689. if (hr != S_OK)
  1690. {
  1691. OutCtl.Output("\nCouldn't write argument at 0x%p.",
  1692. EndIP - sizeof(Argument.I32));
  1693. }
  1694. }
  1695. }
  1696. }
  1697. OutCtl.Output("\n");
  1698. if (hr == S_OK)
  1699. {
  1700. FinalIP = AsmIP;
  1701. if (EndIP - IP > sizeof(OldCode))
  1702. {
  1703. OutCtl.OutErr("Error: Didn't save enough code!\n"
  1704. " Code from 0x%p to 0x%p was trashed.\n",
  1705. IP + sizeof(OldCode), EndIP);
  1706. hr = E_FAIL;
  1707. }
  1708. }
  1709. if (hr == S_OK)
  1710. {
  1711. // Save registers
  1712. if ((hr = Registers->GetNumberRegisters(&RegisterCount)) == S_OK)
  1713. {
  1714. SavedRegisters = (PDEBUG_VALUE) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DEBUG_VALUE)*RegisterCount);
  1715. if (SavedRegisters != NULL)
  1716. {
  1717. if ((hr = Registers->GetValues(RegisterCount, NULL, 0, SavedRegisters)) != S_OK)
  1718. {
  1719. HeapFree(GetProcessHeap(), 0, SavedRegisters);
  1720. SavedRegisters = NULL;
  1721. RegisterCount = 0;
  1722. }
  1723. else
  1724. {
  1725. OutCtl.OutVerb(" Saved %lu registers.\n", RegisterCount);
  1726. }
  1727. }
  1728. else
  1729. {
  1730. RegisterCount = 0;
  1731. hr = E_OUTOFMEMORY;
  1732. }
  1733. }
  1734. if (hr != S_OK)
  1735. {
  1736. OutCtl.Output("Error saving register values.\n");
  1737. }
  1738. }
  1739. if (hr == S_OK)
  1740. {
  1741. CHAR szDisasmCmd[64];
  1742. OutCtl.Output(" Temporary routine placed from 0x%p to 0x%p.\n",
  1743. IP, EndIP);
  1744. OutCtl.Output("Please verify code, especially jumps:\n");
  1745. sprintf(szDisasmCmd, "u 0x%I64x 0x%I64x", IP, EndIP);
  1746. Control->Execute(DEBUG_OUTCTL_THIS_CLIENT,
  1747. szDisasmCmd,
  1748. DEBUG_EXECUTE_NOT_LOGGED |
  1749. DEBUG_EXECUTE_NO_REPEAT);
  1750. OutCtl.Output("Then set IP to 0x%p and run machine.\n", StartIP);
  1751. CodeWritten = TRUE;
  1752. }
  1753. else
  1754. {
  1755. if (Data->WriteVirtual(IP, OldCode, CodeRead, &CodeRestored) != S_OK ||
  1756. CodeRestored != CodeRead)
  1757. {
  1758. OutCtl.OutErr("Error restoring original code.\n");
  1759. }
  1760. }
  1761. }
  1762. }
  1763. }
  1764. else
  1765. {
  1766. HRESULT hrGetIP;
  1767. ULONG64 ResultIP;
  1768. HRESULT hrRestore = S_OK;
  1769. hr = S_OK;
  1770. if ((hrGetIP = Registers->GetInstructionOffset(&ResultIP)) == S_OK)
  1771. {
  1772. if (ResultIP != FinalIP)
  1773. {
  1774. OutCtl.OutWarn("Result IP = 0x%p differs from expected 0x%p.\n",
  1775. ResultIP, FinalIP);
  1776. }
  1777. }
  1778. else
  1779. {
  1780. OutCtl.OutWarn("Unable to confirm result IP.\n");
  1781. ResultIP = (FinalIP == 0) ? -1 : 0;
  1782. }
  1783. if (CodeWritten)
  1784. {
  1785. if (ResultIP == FinalIP ||
  1786. (hrRestore = GetYNInput((PDEBUG_CONTROL)Control, "Restore code anyway?")) == S_OK)
  1787. {
  1788. if ((hr = Data->WriteVirtual(IP, OldCode, CodeRead, &CodeRestored)) == S_OK &&
  1789. CodeRestored == CodeRead)
  1790. {
  1791. CodeWritten = FALSE;
  1792. IP = 0;
  1793. OutCtl.Output("Original code restored.\n");
  1794. }
  1795. else
  1796. {
  1797. OutCtl.OutErr("Error restoring original code.\n");
  1798. if (hr == S_OK) hr = E_FAIL;
  1799. }
  1800. }
  1801. }
  1802. if (hr == S_OK &&
  1803. RegisterCount != 0)
  1804. {
  1805. if (ResultIP == FinalIP ||
  1806. (hrRestore = GetYNInput((PDEBUG_CONTROL)Control, "Restore register values anyway?")) == S_OK)
  1807. {
  1808. DEBUG_VALUE NewRegValue;
  1809. ULONG Register;
  1810. for (Register = 0; Register < RegisterCount && hr == S_OK; Register++)
  1811. {
  1812. __try {
  1813. hr = Registers->SetValue(Register, &SavedRegisters[Register]);
  1814. }
  1815. __except(DebuggerExceptionFilter(GetExceptionInformation(),
  1816. Client,
  1817. "IDebugRegisters", "SetValue"))
  1818. {
  1819. hr = S_FALSE;
  1820. }
  1821. if (hr != S_OK)
  1822. {
  1823. RtlZeroMemory(&NewRegValue, sizeof(NewRegValue));
  1824. if (Registers->GetValue(Register, &NewRegValue) == S_OK)
  1825. {
  1826. if (!RtlEqualMemory(&SavedRegisters[Register], &NewRegValue, sizeof(NewRegValue)))
  1827. {
  1828. OutCtl.OutErr(" Registers %lu's value had changed.\n", Register);
  1829. }
  1830. else
  1831. {
  1832. OutCtl.Output(" However, registers %lu's value had NOT changed.\n", Register);
  1833. hr = S_OK;
  1834. }
  1835. }
  1836. else
  1837. {
  1838. OutCtl.OutErr(" Unable to check register %lu's current value.\n", Register);
  1839. }
  1840. if (hr != S_OK)
  1841. {
  1842. OutCtl.OutErr(" Register %lu's value has not been restored.\n", Register);
  1843. hr = GetYNInput((PDEBUG_CONTROL)Control, "Continue restoring registers?");
  1844. }
  1845. }
  1846. }
  1847. if (hr == S_OK)
  1848. {
  1849. OutCtl.Output("Original register values restored.\n");
  1850. }
  1851. else
  1852. {
  1853. OutCtl.OutErr("Error restoring original register values.\n");
  1854. }
  1855. }
  1856. else
  1857. {
  1858. hr = S_FALSE;
  1859. }
  1860. if (hr != S_OK)
  1861. {
  1862. hr = GetYNInput((PDEBUG_CONTROL)Control, "Discard saved register values?");
  1863. }
  1864. if (hr == S_OK)
  1865. {
  1866. HeapFree(GetProcessHeap(), 0, SavedRegisters);
  1867. SavedRegisters = NULL;
  1868. RegisterCount = 0;
  1869. }
  1870. }
  1871. if (hr == S_OK) hr = hrRestore;
  1872. }
  1873. if (!CodeWritten && RegisterCount == 0)
  1874. {
  1875. if (Symbols != NULL) { Symbols->Release(); Symbols = NULL; }
  1876. if (Registers != NULL) { Registers->Release(); Registers = NULL; }
  1877. if (Data != NULL) { Data->Release(); Data = NULL; }
  1878. if (Control != NULL) { Control->Release(); Control = NULL; }
  1879. }
  1880. return hr;
  1881. }
  1882. Instruction PageInSurfs_x86_Instructions[] = {
  1883. { 0, sizeof(x86_jmp_here), (PSTR) x86_jmp_here}, // To loop here
  1884. { 0, 0, "int 3" },
  1885. { I_START_IP, 0, "push @eax" },
  1886. { 0, 0, "push @ecx" },
  1887. { 0, 0, "push @edx" },
  1888. { 0, 0, "mov @ecx, DWORD PTR [win32k!ghsemShareDevLock]" },
  1889. { 0, 0, "call win32k!GreAcquireSemaphore" },
  1890. { 0, 0, "mov @ecx, DWORD PTR [win32k!ghsemDriverMgmt]" },
  1891. { 0, 0, "call win32k!GreAcquireSemaphore" },
  1892. { 0, 0, "mov @ecx, DWORD PTR [win32k!ghsemHmgr]" },
  1893. { 0, 0, "call win32k!GreAcquireSemaphore" },
  1894. { 0, 0, "xor @ecx, @ecx" },
  1895. { 0, sizeof(x86_jmp_plus_0x0e), (PSTR) x86_jmp_plus_0x0e}, // To loop condition
  1896. // Loop start
  1897. { 0, 0, "mov @ecx, DWORD PTR [@eax]" },
  1898. { 0, 0, "mov @eax, DWORD PTR [@eax+0x30]" },
  1899. { 0, 0, "cmp @eax, 0x80000000" },
  1900. { 0, sizeof(x86_jb_plus_0x02), (PSTR) x86_jb_plus_0x02}, // To loop condition
  1901. { 0, 0, "mov @eax, DWORD PTR [@eax]" },
  1902. // Loop condition
  1903. { 0, 0, "mov @dl, 5" },
  1904. { 0, 0, "call win32k!HmgSafeNextObjt" },
  1905. { 0, 0, "test @eax, @eax" },
  1906. { 0, sizeof(x86_jne_minus_0x18), (PSTR) x86_jne_minus_0x18}, // To loop start
  1907. { 0, 0, "mov @ecx, DWORD PTR [win32k!ghsemHmgr]" },
  1908. { 0, 0, "call win32k!GreReleaseSemaphore" },
  1909. { 0, 0, "mov @ecx, DWORD PTR [win32k!ghsemDriverMgmt]" },
  1910. { 0, 0, "call win32k!GreReleaseSemaphore" },
  1911. { 0, 0, "mov @ecx, DWORD PTR [win32k!ghsemShareDevLock]" },
  1912. { 0, 0, "call win32k!GreReleaseSemaphore" },
  1913. { 0, 0, "pop @edx" },
  1914. { 0, 0, "pop @ecx" },
  1915. { 0, 0, "pop @eax" },
  1916. { 0, 0, "int 3" },
  1917. { 0, 0, NULL }
  1918. };
  1919. DECLARE_API( pageinsurfs )
  1920. {
  1921. BEGIN_API( pageinsurfs );
  1922. HRESULT hr = S_OK;
  1923. OutputControl OutCtl(Client);
  1924. Instruction *instructions;
  1925. switch (TargetMachine)
  1926. {
  1927. case IMAGE_FILE_MACHINE_I386:
  1928. instructions = PageInSurfs_x86_Instructions;
  1929. break;
  1930. default:
  1931. {
  1932. OutCtl.OutWarn("This extension is only supported on x86 architectures.\n");
  1933. hr = E_NOTIMPL;
  1934. break;
  1935. }
  1936. }
  1937. if (hr == S_OK)
  1938. {
  1939. hr = AssembleTempRoutine(Client, instructions, args);
  1940. }
  1941. return hr;
  1942. }
  1943. Instruction PageInSurface_x86_Instructions[] = {
  1944. { 0, sizeof(x86_jmp_here), (PSTR) x86_jmp_here}, // To loop here
  1945. { 0, 0, "int 3" },
  1946. {I_START_IP, 0, "push @eax" },
  1947. { 0, 0, "push @ecx" },
  1948. { 0, 0, "push @edx" },
  1949. { 0, 0, "push @esi" },
  1950. { 0, 0, "mov @ecx, DWORD PTR [win32k!ghsemShareDevLock]" },
  1951. { 0, 0, "call win32k!GreAcquireSemaphore" },
  1952. { 0, 0, "mov @ecx, DWORD PTR [win32k!ghsemDriverMgmt]" },
  1953. { 0, 0, "call win32k!GreAcquireSemaphore" },
  1954. { 0, 0, "mov @ecx, DWORD PTR [win32k!ghsemHmgr]" },
  1955. { 0, 0, "call win32k!GreAcquireSemaphore" },
  1956. {I_WRITE_ADDRESS, 0, "mov @edx, 0xDeadBeef" },
  1957. { 0, 0, "mov @esi, DWORD PTR [@edx+0x30]" }, // pvScan0
  1958. { 0, 0, "cmp @esi, 0x80000000" }, // Check User address/NULL
  1959. { 0, 0, "mov @ecx, DWORD PTR [@edx+0x24]" }, // sizlBitmap.cy
  1960. { 0, sizeof(x86_jb_plus_0x0c), (PSTR) x86_jb_plus_0x0c}, // To end
  1961. { 0, 0, "test @ecx, @ecx" }, // Check scan
  1962. { 0, sizeof(x86_jmp_plus_0x06), (PSTR) x86_jmp_plus_0x06}, // To loop condition
  1963. // Loop start
  1964. { 0, 0, "mov @eax, DWORD PTR [@esi]" },
  1965. { 0, 0, "add @esi, DWORD PTR [@edx+0x34]" }, // lDelta
  1966. { 0, 0, "dec @ecx" },
  1967. // Loop condition
  1968. { 0, sizeof(x86_jnz_minus_0x08), (PSTR) x86_jnz_minus_0x08}, // To loop start
  1969. // End
  1970. { 0, 0, "mov @ecx, DWORD PTR [win32k!ghsemHmgr]" },
  1971. { 0, 0, "call win32k!GreReleaseSemaphore" },
  1972. { 0, 0, "mov @ecx, DWORD PTR [win32k!ghsemDriverMgmt]" },
  1973. { 0, 0, "call win32k!GreReleaseSemaphore" },
  1974. { 0, 0, "mov @ecx, DWORD PTR [win32k!ghsemShareDevLock]" },
  1975. { 0, 0, "call win32k!GreReleaseSemaphore" },
  1976. { 0, 0, "pop @esi" },
  1977. { 0, 0, "pop @edx" },
  1978. { 0, 0, "pop @ecx" },
  1979. { 0, 0, "pop @eax" },
  1980. { 0, 0, "int 3" },
  1981. { 0, 0, NULL }
  1982. };
  1983. DECLARE_API( pageinsurface )
  1984. {
  1985. BEGIN_API( pageinsurface );
  1986. HRESULT hr = S_OK;
  1987. OutputControl OutCtl(Client);
  1988. Instruction *instructions;
  1989. switch (TargetMachine)
  1990. {
  1991. case IMAGE_FILE_MACHINE_I386:
  1992. instructions = PageInSurface_x86_Instructions;
  1993. break;
  1994. default:
  1995. {
  1996. OutCtl.OutWarn("This extension is only supported on x86 architectures.\n");
  1997. hr = E_NOTIMPL;
  1998. break;
  1999. }
  2000. }
  2001. if (hr == S_OK)
  2002. {
  2003. hr = AssembleTempRoutine(Client, instructions, args);
  2004. }
  2005. return hr;
  2006. }