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.

598 lines
18 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. region.cxx
  5. Abstract:
  6. This file contains the routines to debug regions.
  7. Author:
  8. Jason Hartman (JasonHa) 2001-04-30
  9. Environment:
  10. User Mode
  11. --*/
  12. #include "precomp.hxx"
  13. /******************************Public*Routine******************************\
  14. * DECLARE_API( dr )
  15. *
  16. * Debugger extension to dump a region
  17. *
  18. * 21-Feb-1995 -by- Lingyun Wang [lingyunw]
  19. * Wrote it.
  20. \**************************************************************************/
  21. DECLARE_API( dr )
  22. {
  23. OutputControl OutCtl(Client);
  24. OutCtl.Output("Obsolete: Use 'region hrgn|prgn'.\n");
  25. return S_OK;
  26. }
  27. /******************************Public*Routine******************************\
  28. * DECLARE_API( cr )
  29. *
  30. * Debugger extension to check a region
  31. *
  32. * 21-Feb-1995 -by- Lingyun Wang [lingyunw]
  33. * Wrote it.
  34. \**************************************************************************/
  35. DECLARE_API( cr )
  36. {
  37. OutputControl OutCtl(Client);
  38. OutCtl.Output("Obsolete: Use 'region -c hrgn|prgn'\n");
  39. return S_OK;
  40. }
  41. /******************************Public*Routine******************************\
  42. * DECLARE_API( region )
  43. *
  44. * Debugger extension to dump and validate a region
  45. *
  46. * 22-May-2000 -by- Jason Hartman [jasonha]
  47. * Converted from old dr & cr
  48. *
  49. \**************************************************************************/
  50. DECLARE_API( region )
  51. {
  52. ULONG64 RgnAddr;
  53. ULONG error;
  54. ULONG Flags = 0;
  55. #define REGION_CSCANS 0
  56. #define REGION_SCAN_ADDRESS 1
  57. #define REGION_SCAN_TAIL 2
  58. #define REGION_SIZEOBJ 3
  59. #define NUM_REGION_BASEOBJ_FIELDS 3
  60. FIELD_INFO RegionFields[] = {
  61. { DbgStr("cScans"), DbgStr("cScans :"), 0, DBG_DUMP_FIELD_FULL_NAME, 0, NULL}, // REGION_CSCANS
  62. { DbgStr("scan"), DbgStr("scan <- pscnHead :"), 0, DBG_DUMP_FIELD_RETURN_ADDRESS | DBG_DUMP_FIELD_FULL_NAME, 0, AddressPrintCallback}, // REGION_SCAN_ADDRESS
  63. { DbgStr("pscnTail"), DbgStr("pscnTail :"), 0, DBG_DUMP_FIELD_FULL_NAME, 0, NULL}, // REGION_SCAN_TAIL
  64. { DbgStr("sizeObj"), DbgStr("sizeObj :"), 0, DBG_DUMP_FIELD_FULL_NAME, 0, NULL}, // REGION_SIZEOBJ
  65. { DbgStr("sizeRgn"), DbgStr("sizeRgn :"), 0, DBG_DUMP_FIELD_FULL_NAME, 0, NULL},
  66. { DbgStr("cRefs"), DbgStr("cRefs :"), 0, DBG_DUMP_FIELD_FULL_NAME, 0, NULL},
  67. { DbgStr("rcl"), DbgStr("rcl :"), 0, DBG_DUMP_FIELD_RETURN_ADDRESS | DBG_DUMP_FIELD_FULL_NAME, 0, RECTLCallback},
  68. { DbgStr("hHmgr"), DbgStr("hHmgr :"), 0, DBG_DUMP_FIELD_FULL_NAME, 0, NULL},
  69. { DbgStr("cExclusiveLock"), DbgStr("cExclusiveLock :"), 0, DBG_DUMP_FIELD_FULL_NAME, 0, NULL},
  70. { DbgStr("Tid"), DbgStr("Tid :"), 0, DBG_DUMP_FIELD_FULL_NAME, 0, NULL},
  71. };
  72. SYM_DUMP_PARAM RegionSym = {
  73. sizeof (SYM_DUMP_PARAM), DbgStr(GDIType(REGION)), DBG_DUMP_COMPACT_OUT, 0/*RgnAddr*/,
  74. NULL, &RegionSym, NewlineCallback, sizeof(RegionFields)/sizeof(RegionFields[0]), RegionFields
  75. };
  76. PrepareCallbacks(TRUE);
  77. INIT_API();
  78. PARSE_POINTER(region_help);
  79. if (ntok > 1)
  80. {
  81. if (parse_iFindSwitch(tokens, ntok, 'c')!=-1)
  82. {
  83. Flags |= SCAN_DUMPER_NO_PRINT;
  84. }
  85. else if (parse_iFindSwitch(tokens, ntok, 'f')!=-1)
  86. {
  87. Flags |= SCAN_DUMPER_FORCE;
  88. }
  89. if (parse_iFindSwitch(tokens, ntok, 'r')!=-1)
  90. {
  91. Flags |= SCAN_DUMPER_FROM_TAIL;
  92. }
  93. }
  94. // get pointer to object from handle or use param as pointer
  95. if ((GetObjectAddress(Client,arg,&RgnAddr,RGN_TYPE,TRUE,TRUE) != S_OK) ||
  96. (RgnAddr == 0))
  97. {
  98. ULONG64 ObjHandle;
  99. ULONG64 RgnAddrFromHmgr;
  100. RgnAddr = arg;
  101. if (error = GetFieldValue(RgnAddr, GDIType(REGION), "hHmgr", ObjHandle))
  102. {
  103. ExtErr("Unable to get contents of REGION::hHmgr\n");
  104. ExtErr(" (Ioctl returned %s)\n", pszWinDbgError(error));
  105. ExtErr(" %#p is neither an HRGN nor valid REGION address\n", arg);
  106. EXIT_API(S_OK);
  107. }
  108. if (!ObjHandle)
  109. {
  110. ExtOut("\tREGION is reserved for system use (no handle manger entry).\n");
  111. RegionSym.nFields -= NUM_REGION_BASEOBJ_FIELDS;
  112. }
  113. else if (GetObjectAddress(Client,ObjHandle,&RgnAddrFromHmgr,
  114. RGN_TYPE,TRUE,FALSE) == S_OK &&
  115. RgnAddrFromHmgr != RgnAddr)
  116. {
  117. ExtOut("\tNote: REGION may not be valid.\n\t It does not have a valid handle manager entry.\n");
  118. }
  119. }
  120. ExtOut("REGION @ %#p\n ", RgnAddr);
  121. RegionSym.addr = RgnAddr;
  122. error = Ioctl( IG_DUMP_SYMBOL_INFO, &RegionSym, RegionSym.size );
  123. if (error)
  124. {
  125. ExtErr("Unable to get contents of REGION\n");
  126. ExtErr(" (Ioctl returned %s)\n", pszWinDbgError(error));
  127. }
  128. else
  129. {
  130. ScanDumper Dumper(RegionFields[REGION_SCAN_ADDRESS].address,
  131. RegionFields[REGION_SCAN_TAIL].address,
  132. (ULONG)RegionFields[REGION_CSCANS].address,
  133. RegionFields[REGION_SCAN_ADDRESS].address,
  134. RgnAddr+RegionFields[REGION_SIZEOBJ].address,
  135. Flags
  136. );
  137. BOOL Valid;
  138. if ((Flags & SCAN_DUMPER_FROM_TAIL) != 0 && !Dumper.Reverse)
  139. {
  140. // We rquested a reverse dump, but Dumper wouldn't allow it.
  141. EXIT_API(S_OK);
  142. }
  143. Valid = Dumper.DumpScans((ULONG)RegionFields[REGION_CSCANS].address);
  144. if (Dumper.Reverse)
  145. {
  146. if (Dumper.ScanAddr != RegionFields[REGION_SCAN_ADDRESS].address)
  147. {
  148. ExtOut(" * Final ScanAddr (%#p) is not at head address (%#p)\n",
  149. Dumper.ScanAddr, RegionFields[REGION_SCAN_ADDRESS].address);
  150. Valid = FALSE;
  151. }
  152. }
  153. else
  154. {
  155. if (Dumper.ScanAddr != RegionFields[REGION_SCAN_TAIL].address)
  156. {
  157. ExtOut(" * Final ScanAddr (%#p) is not at tail address (%#p)\n",
  158. Dumper.ScanAddr, RegionFields[REGION_SCAN_TAIL].address);
  159. Valid = FALSE;
  160. }
  161. }
  162. if (Valid)
  163. {
  164. ExtOut(" Region is valid.\n");
  165. }
  166. else
  167. {
  168. ExtOut(" Region is NOT valid.\n");
  169. }
  170. }
  171. EXIT_API(S_OK);
  172. region_help:
  173. ExtOut("Usage: region [-?cfr] hrgn|prgn\n");
  174. ExtOut(" dumps/validates a region\n");
  175. ExtOut(" c - doesn't print scans; validation only\n");
  176. ExtOut(" f - continue printing even if an error is found\n");
  177. ExtOut(" r - read scans in reverse order\n");
  178. EXIT_API(S_OK);
  179. }
  180. /**************************************************************************\
  181. *
  182. \**************************************************************************/
  183. BOOL bStrInStr(CHAR *pchTrg, CHAR *pchSrc)
  184. {
  185. BOOL bRes = 0;
  186. int c = strlen(pchSrc);
  187. //CHECKLOOP umm? This could be difficult to detect
  188. while (TRUE)
  189. {
  190. // find the first character
  191. pchTrg = strchr(pchTrg,*pchSrc);
  192. // didn't find it?, fail!
  193. if (pchTrg == NULL)
  194. return(FALSE);
  195. // did we find the string? succeed
  196. if (strncmp(pchTrg,pchSrc,c) == 0)
  197. return(TRUE);
  198. // go get the next one.
  199. pchTrg++;
  200. }
  201. }
  202. /******************************Public*Routine******************************\
  203. * rgnlog
  204. *
  205. \**************************************************************************/
  206. #define MAXSEARCH 4
  207. DECLARE_API( rgnlog )
  208. {
  209. #if 1
  210. HRESULT hr = S_OK;
  211. BOOL BadArg = FALSE;
  212. ULONG RemainingArgIndex;
  213. DEBUG_VALUE DumpCount = { 0, DEBUG_VALUE_INVALID };
  214. CHAR EmptySearchString[] = "";
  215. PSTR SearchStringList = EmptySearchString;
  216. PSTR SearchString = SearchStringList;
  217. OutputControl OutCtl(Client);
  218. while (!BadArg && hr == S_OK)
  219. {
  220. while (isspace(*args)) args++;
  221. if (*args == '-')
  222. {
  223. args++;
  224. if (*args == '\0' || isspace(*args))
  225. {
  226. BadArg = TRUE;
  227. }
  228. else if (DumpCount.Type == DEBUG_VALUE_INVALID &&
  229. args[0] == '1' && (args[1] == '\0' || isspace(args[1])))
  230. {
  231. DumpCount.I32 = -1;
  232. DumpCount.Type = DEBUG_VALUE_INT32;
  233. }
  234. else
  235. {
  236. while (*args != '\0' && !isspace(*args))
  237. {
  238. switch (*args)
  239. {
  240. case '?':
  241. default:
  242. BadArg = TRUE;
  243. break;
  244. }
  245. if (BadArg) break;
  246. args++;
  247. }
  248. }
  249. }
  250. else
  251. {
  252. if (DumpCount.Type == DEBUG_VALUE_INVALID)
  253. {
  254. if (Evaluate(Client, args, DEBUG_VALUE_INT32, EVALUATE_DEFAULT_RADIX,
  255. &DumpCount, &RemainingArgIndex, NULL, EVALUATE_COMPACT_EXPR) != S_OK ||
  256. DumpCount.I32 == 0)
  257. {
  258. BadArg = TRUE;
  259. }
  260. else
  261. {
  262. args += RemainingArgIndex;
  263. }
  264. }
  265. else
  266. {
  267. if (SearchStringList == EmptySearchString)
  268. {
  269. SearchStringList = (PSTR)HeapAlloc(GetProcessHeap(), 0,
  270. sizeof(*SearchStringList)*(strlen(args)+2));
  271. if (SearchStringList == NULL)
  272. {
  273. hr = E_OUTOFMEMORY;
  274. }
  275. else
  276. {
  277. SearchString = SearchStringList;
  278. *SearchString = '\0';
  279. }
  280. }
  281. if (hr == S_OK)
  282. {
  283. if (*args == '`' || *args == '\'' || *args == '\"')
  284. {
  285. CHAR StringEnd = *args;
  286. if (args[1] == StringEnd || args[1] == '\0')
  287. {
  288. BadArg = TRUE;
  289. }
  290. else
  291. {
  292. while (*args != StringEnd && *args != '\0')
  293. {
  294. *SearchString++ = *args++;
  295. }
  296. if (*args == StringEnd) args++;
  297. if (!isspace(*args) || *args != '\0')
  298. {
  299. OutCtl.Output("Malformed Search String at '%s'.\n",
  300. args);
  301. BadArg = TRUE;
  302. }
  303. else
  304. {
  305. *SearchString++ = '\0';
  306. }
  307. }
  308. }
  309. else
  310. {
  311. while (!isspace(*args) && *args != '\0')
  312. {
  313. *SearchString++ = *args++;
  314. }
  315. *SearchString++ = '\0';
  316. }
  317. }
  318. }
  319. }
  320. }
  321. if (hr == S_OK)
  322. {
  323. if (BadArg)
  324. {
  325. if (*args == '?') OutCtl.Output("rgnlog - dump/search rgnlog from checked builds.\n");
  326. OutCtl.Output("Usage: rgnlog [-?] <Entries> [<Search Strings>]\n"
  327. "\n"
  328. " Entries - Number of tailing entries to dump/search\n"
  329. " Search Strings - Dump only logs contain one of strings specified\n");
  330. }
  331. else
  332. {
  333. // Mark end of search string list with a NULL string.
  334. *SearchString = '\0';
  335. LONG iLog, iPass;
  336. ULONG LogArraySize, LogLength, LogEntrySize;
  337. CHAR SymName[80];
  338. sprintf(SymName, "%s!iLog", GDIKM_Module.Name);
  339. hr = ReadSymbolData(Client, SymName, &iLog, sizeof(iLog), NULL);
  340. if (hr != S_OK) OutCtl.OutErr("Unable to get contents of %s\n", SymName);
  341. if (hr == S_OK)
  342. {
  343. sprintf(SymName, "%s!iPass", GDIKM_Module.Name);
  344. hr = ReadSymbolData(Client, SymName, &iPass, sizeof(iPass), NULL);
  345. if (hr != S_OK) OutCtl.OutErr("Unable to get contents of %s\n", SymName);
  346. }
  347. if (hr == S_OK)
  348. {
  349. sprintf(SymName, "%s!argnlog", GDIKM_Module.Name);
  350. hr = GetArrayDimensions(Client, SymName, NULL,
  351. &LogArraySize, &LogLength, &LogEntrySize);
  352. if (hr != S_OK) OutCtl.OutErr("Unable to get dimensions of %s\n", SymName);
  353. }
  354. if (hr == S_OK)
  355. {
  356. }
  357. if (hr == S_OK)
  358. {
  359. if (*SearchStringList != '\0')
  360. {
  361. OutCtl.Output("Searching last %ld entries for:\n",
  362. DumpCount.I32);
  363. for (SearchString = SearchStringList;
  364. *SearchString != '\0';
  365. *SearchString += strlen(SearchString)+1)
  366. {
  367. OutCtl.Output(" \"%s\"\n", SearchString);
  368. }
  369. }
  370. else
  371. {
  372. OutCtl.Output("Dumping last %ld entries.\n",
  373. DumpCount.I32);
  374. }
  375. // To Do
  376. }
  377. }
  378. }
  379. if (SearchStringList != EmptySearchString)
  380. {
  381. HeapFree(GetProcessHeap(), 0, SearchStringList);
  382. }
  383. return hr;
  384. #else
  385. dprintf("Extension 'rgnlog' is not converted.\n");
  386. #if ENABLE_OLD_EXTS // DOES NOT SUPPORT API64
  387. LONG cDump;
  388. LONG iCurrent;
  389. RGNLOGENTRY rl;
  390. RGNLOGENTRY *prl;
  391. LONG gml; // gMaxRgnLog
  392. int i, j;
  393. PVOID pv;
  394. CHAR achTmp[30];
  395. CHAR achBuf[256];
  396. PCHAR pchS[MAXSEARCH];
  397. int cSearch;
  398. BOOL bPrint;
  399. PARSE_ARGUMENTS(rgnlog_help);
  400. if(ntok<1) { goto rgnlog_help; }
  401. tok_pos = parse_FindNonSwitch(tokens, ntok);
  402. if(tok_pos==-1) { goto rgnlog_help; }
  403. //check that this supports decimal
  404. cDump = (LONG)GetExpression(tokens[tok_pos]);
  405. if(cDump==0) { goto rgnlog_help; }
  406. cSearch = 0;
  407. while(cSearch<MAXSEARCH) {
  408. tok_pos = parse_FindNonSwitch(tokens, ntok, tok_pos+1);
  409. if(tok_pos==-1) {break;}
  410. pchS[cSearch]=tokens[tok_pos];
  411. cSearch++;
  412. }
  413. for (i = 0; i < cSearch; ++i)
  414. dprintf("search[%s]\n",pchS[i]);
  415. // get some stuff
  416. GetAddress(pv, "&win32k!iLog");
  417. dprintf("&iLog = %lx\n",pv);
  418. if (pv == NULL)
  419. {
  420. dprintf("iCurrent was NULL\n");
  421. return;
  422. }
  423. move(iCurrent, pv);
  424. GetAddress(i,"&win32k!iPass");
  425. if (pv == NULL)
  426. {
  427. dprintf("iPass was NULL\n");
  428. return;
  429. }
  430. move(i,i);
  431. dprintf("--------------------------------------------------\n");
  432. dprintf("rgn log list, cDump = %ld, iCur = %ld, iPass = %ld\n", cDump,iCurrent,i);
  433. dprintf("%5s-%4s:%8s,%8s,(%8s),%8s,%8s,%4s\n",
  434. "TEB ","i","hrgn","prgn","return","arg1","arg2","arg3");
  435. dprintf("--------------------------------------------------\n");
  436. // Dereference the handle via the engine's handle manager.
  437. GetAddress(prl, "win32k!argnlog");
  438. if (!prl)
  439. {
  440. dprintf("prl was NULL\n");
  441. return;
  442. }
  443. GetAddress(gml, "&win32k!gMaxRgnLog");
  444. if (!gml)
  445. {
  446. dprintf("gml was NULL\n");
  447. return;
  448. }
  449. move(gml,gml);
  450. // set iCurrent to the first thing to dump
  451. if (cDump > gml)
  452. cDump = gml;
  453. if (cDump > iCurrent)
  454. iCurrent += gml;
  455. iCurrent -= cDump;
  456. dprintf("prl = %lx, gml = %ld, cDump = %ld, iCurrent = %ld\n",prl,gml,cDump,iCurrent);
  457. //CHECKLOOP add exit/more support
  458. for (i = 0; i < cDump; ++i)
  459. {
  460. move(rl,&prl[iCurrent]);
  461. if (rl.pszOperation != NULL)
  462. {
  463. move2(achTmp,rl.pszOperation,30);
  464. }
  465. else
  466. achTmp[0] = 0;
  467. sprintf(achBuf,"%5lx-%4ld:%p,%p,(%8lx),%p, %p,%p, %s, %p, %p\n",
  468. (ULONG_PTR)rl.teb >> 12,iCurrent,rl.hrgn,rl.prgn,rl.lRes,rl.lParm1,
  469. rl.lParm2,rl.lParm3,achTmp,rl.pvCaller,rl.pvCallersCaller);
  470. bPrint = (cSearch == 0);
  471. for (j = 0; (j < cSearch) && !bPrint; ++j)
  472. bPrint |= bStrInStr(achBuf,pchS[j]);
  473. if (bPrint)
  474. {
  475. dprintf(achBuf);
  476. }
  477. if (++iCurrent >= gml)
  478. iCurrent = 0;
  479. if (CheckControlC())
  480. return;
  481. }
  482. return;
  483. rgnlog_help:
  484. dprintf("\n rgnlog nnn [search1] [search2] [search3] [search4]\n");
  485. dprintf("\t nnn - dumps the last n entries of the rgn log\n");
  486. dprintf("\t search[n] - displays only entries containing one of n strings\n");
  487. dprintf("\t NOTE: only works on checked builds. you must set bLogRgn at run time\n");
  488. #endif // DOES NOT SUPPORT API64
  489. EXIT_API(S_OK);
  490. #endif
  491. }