/*++ Copyright (c) 2001 Microsoft Corporation Module Name: region.cxx Abstract: This file contains the routines to debug regions. Author: Jason Hartman (JasonHa) 2001-04-30 Environment: User Mode --*/ #include "precomp.hxx" /******************************Public*Routine******************************\ * DECLARE_API( dr ) * * Debugger extension to dump a region * * 21-Feb-1995 -by- Lingyun Wang [lingyunw] * Wrote it. \**************************************************************************/ DECLARE_API( dr ) { OutputControl OutCtl(Client); OutCtl.Output("Obsolete: Use 'region hrgn|prgn'.\n"); return S_OK; } /******************************Public*Routine******************************\ * DECLARE_API( cr ) * * Debugger extension to check a region * * 21-Feb-1995 -by- Lingyun Wang [lingyunw] * Wrote it. \**************************************************************************/ DECLARE_API( cr ) { OutputControl OutCtl(Client); OutCtl.Output("Obsolete: Use 'region -c hrgn|prgn'\n"); return S_OK; } /******************************Public*Routine******************************\ * DECLARE_API( region ) * * Debugger extension to dump and validate a region * * 22-May-2000 -by- Jason Hartman [jasonha] * Converted from old dr & cr * \**************************************************************************/ DECLARE_API( region ) { ULONG64 RgnAddr; ULONG error; ULONG Flags = 0; #define REGION_CSCANS 0 #define REGION_SCAN_ADDRESS 1 #define REGION_SCAN_TAIL 2 #define REGION_SIZEOBJ 3 #define NUM_REGION_BASEOBJ_FIELDS 3 FIELD_INFO RegionFields[] = { { DbgStr("cScans"), DbgStr("cScans :"), 0, DBG_DUMP_FIELD_FULL_NAME, 0, NULL}, // REGION_CSCANS { DbgStr("scan"), DbgStr("scan <- pscnHead :"), 0, DBG_DUMP_FIELD_RETURN_ADDRESS | DBG_DUMP_FIELD_FULL_NAME, 0, AddressPrintCallback}, // REGION_SCAN_ADDRESS { DbgStr("pscnTail"), DbgStr("pscnTail :"), 0, DBG_DUMP_FIELD_FULL_NAME, 0, NULL}, // REGION_SCAN_TAIL { DbgStr("sizeObj"), DbgStr("sizeObj :"), 0, DBG_DUMP_FIELD_FULL_NAME, 0, NULL}, // REGION_SIZEOBJ { DbgStr("sizeRgn"), DbgStr("sizeRgn :"), 0, DBG_DUMP_FIELD_FULL_NAME, 0, NULL}, { DbgStr("cRefs"), DbgStr("cRefs :"), 0, DBG_DUMP_FIELD_FULL_NAME, 0, NULL}, { DbgStr("rcl"), DbgStr("rcl :"), 0, DBG_DUMP_FIELD_RETURN_ADDRESS | DBG_DUMP_FIELD_FULL_NAME, 0, RECTLCallback}, { DbgStr("hHmgr"), DbgStr("hHmgr :"), 0, DBG_DUMP_FIELD_FULL_NAME, 0, NULL}, { DbgStr("cExclusiveLock"), DbgStr("cExclusiveLock :"), 0, DBG_DUMP_FIELD_FULL_NAME, 0, NULL}, { DbgStr("Tid"), DbgStr("Tid :"), 0, DBG_DUMP_FIELD_FULL_NAME, 0, NULL}, }; SYM_DUMP_PARAM RegionSym = { sizeof (SYM_DUMP_PARAM), DbgStr(GDIType(REGION)), DBG_DUMP_COMPACT_OUT, 0/*RgnAddr*/, NULL, &RegionSym, NewlineCallback, sizeof(RegionFields)/sizeof(RegionFields[0]), RegionFields }; PrepareCallbacks(TRUE); INIT_API(); PARSE_POINTER(region_help); if (ntok > 1) { if (parse_iFindSwitch(tokens, ntok, 'c')!=-1) { Flags |= SCAN_DUMPER_NO_PRINT; } else if (parse_iFindSwitch(tokens, ntok, 'f')!=-1) { Flags |= SCAN_DUMPER_FORCE; } if (parse_iFindSwitch(tokens, ntok, 'r')!=-1) { Flags |= SCAN_DUMPER_FROM_TAIL; } } // get pointer to object from handle or use param as pointer if ((GetObjectAddress(Client,arg,&RgnAddr,RGN_TYPE,TRUE,TRUE) != S_OK) || (RgnAddr == 0)) { ULONG64 ObjHandle; ULONG64 RgnAddrFromHmgr; RgnAddr = arg; if (error = GetFieldValue(RgnAddr, GDIType(REGION), "hHmgr", ObjHandle)) { ExtErr("Unable to get contents of REGION::hHmgr\n"); ExtErr(" (Ioctl returned %s)\n", pszWinDbgError(error)); ExtErr(" %#p is neither an HRGN nor valid REGION address\n", arg); EXIT_API(S_OK); } if (!ObjHandle) { ExtOut("\tREGION is reserved for system use (no handle manger entry).\n"); RegionSym.nFields -= NUM_REGION_BASEOBJ_FIELDS; } else if (GetObjectAddress(Client,ObjHandle,&RgnAddrFromHmgr, RGN_TYPE,TRUE,FALSE) == S_OK && RgnAddrFromHmgr != RgnAddr) { ExtOut("\tNote: REGION may not be valid.\n\t It does not have a valid handle manager entry.\n"); } } ExtOut("REGION @ %#p\n ", RgnAddr); RegionSym.addr = RgnAddr; error = Ioctl( IG_DUMP_SYMBOL_INFO, &RegionSym, RegionSym.size ); if (error) { ExtErr("Unable to get contents of REGION\n"); ExtErr(" (Ioctl returned %s)\n", pszWinDbgError(error)); } else { ScanDumper Dumper(RegionFields[REGION_SCAN_ADDRESS].address, RegionFields[REGION_SCAN_TAIL].address, (ULONG)RegionFields[REGION_CSCANS].address, RegionFields[REGION_SCAN_ADDRESS].address, RgnAddr+RegionFields[REGION_SIZEOBJ].address, Flags ); BOOL Valid; if ((Flags & SCAN_DUMPER_FROM_TAIL) != 0 && !Dumper.Reverse) { // We rquested a reverse dump, but Dumper wouldn't allow it. EXIT_API(S_OK); } Valid = Dumper.DumpScans((ULONG)RegionFields[REGION_CSCANS].address); if (Dumper.Reverse) { if (Dumper.ScanAddr != RegionFields[REGION_SCAN_ADDRESS].address) { ExtOut(" * Final ScanAddr (%#p) is not at head address (%#p)\n", Dumper.ScanAddr, RegionFields[REGION_SCAN_ADDRESS].address); Valid = FALSE; } } else { if (Dumper.ScanAddr != RegionFields[REGION_SCAN_TAIL].address) { ExtOut(" * Final ScanAddr (%#p) is not at tail address (%#p)\n", Dumper.ScanAddr, RegionFields[REGION_SCAN_TAIL].address); Valid = FALSE; } } if (Valid) { ExtOut(" Region is valid.\n"); } else { ExtOut(" Region is NOT valid.\n"); } } EXIT_API(S_OK); region_help: ExtOut("Usage: region [-?cfr] hrgn|prgn\n"); ExtOut(" dumps/validates a region\n"); ExtOut(" c - doesn't print scans; validation only\n"); ExtOut(" f - continue printing even if an error is found\n"); ExtOut(" r - read scans in reverse order\n"); EXIT_API(S_OK); } /**************************************************************************\ * \**************************************************************************/ BOOL bStrInStr(CHAR *pchTrg, CHAR *pchSrc) { BOOL bRes = 0; int c = strlen(pchSrc); //CHECKLOOP umm? This could be difficult to detect while (TRUE) { // find the first character pchTrg = strchr(pchTrg,*pchSrc); // didn't find it?, fail! if (pchTrg == NULL) return(FALSE); // did we find the string? succeed if (strncmp(pchTrg,pchSrc,c) == 0) return(TRUE); // go get the next one. pchTrg++; } } /******************************Public*Routine******************************\ * rgnlog * \**************************************************************************/ #define MAXSEARCH 4 DECLARE_API( rgnlog ) { #if 1 HRESULT hr = S_OK; BOOL BadArg = FALSE; ULONG RemainingArgIndex; DEBUG_VALUE DumpCount = { 0, DEBUG_VALUE_INVALID }; CHAR EmptySearchString[] = ""; PSTR SearchStringList = EmptySearchString; PSTR SearchString = SearchStringList; OutputControl OutCtl(Client); while (!BadArg && hr == S_OK) { while (isspace(*args)) args++; if (*args == '-') { args++; if (*args == '\0' || isspace(*args)) { BadArg = TRUE; } else if (DumpCount.Type == DEBUG_VALUE_INVALID && args[0] == '1' && (args[1] == '\0' || isspace(args[1]))) { DumpCount.I32 = -1; DumpCount.Type = DEBUG_VALUE_INT32; } else { while (*args != '\0' && !isspace(*args)) { switch (*args) { case '?': default: BadArg = TRUE; break; } if (BadArg) break; args++; } } } else { if (DumpCount.Type == DEBUG_VALUE_INVALID) { if (Evaluate(Client, args, DEBUG_VALUE_INT32, EVALUATE_DEFAULT_RADIX, &DumpCount, &RemainingArgIndex, NULL, EVALUATE_COMPACT_EXPR) != S_OK || DumpCount.I32 == 0) { BadArg = TRUE; } else { args += RemainingArgIndex; } } else { if (SearchStringList == EmptySearchString) { SearchStringList = (PSTR)HeapAlloc(GetProcessHeap(), 0, sizeof(*SearchStringList)*(strlen(args)+2)); if (SearchStringList == NULL) { hr = E_OUTOFMEMORY; } else { SearchString = SearchStringList; *SearchString = '\0'; } } if (hr == S_OK) { if (*args == '`' || *args == '\'' || *args == '\"') { CHAR StringEnd = *args; if (args[1] == StringEnd || args[1] == '\0') { BadArg = TRUE; } else { while (*args != StringEnd && *args != '\0') { *SearchString++ = *args++; } if (*args == StringEnd) args++; if (!isspace(*args) || *args != '\0') { OutCtl.Output("Malformed Search String at '%s'.\n", args); BadArg = TRUE; } else { *SearchString++ = '\0'; } } } else { while (!isspace(*args) && *args != '\0') { *SearchString++ = *args++; } *SearchString++ = '\0'; } } } } } if (hr == S_OK) { if (BadArg) { if (*args == '?') OutCtl.Output("rgnlog - dump/search rgnlog from checked builds.\n"); OutCtl.Output("Usage: rgnlog [-?] []\n" "\n" " Entries - Number of tailing entries to dump/search\n" " Search Strings - Dump only logs contain one of strings specified\n"); } else { // Mark end of search string list with a NULL string. *SearchString = '\0'; LONG iLog, iPass; ULONG LogArraySize, LogLength, LogEntrySize; CHAR SymName[80]; sprintf(SymName, "%s!iLog", GDIKM_Module.Name); hr = ReadSymbolData(Client, SymName, &iLog, sizeof(iLog), NULL); if (hr != S_OK) OutCtl.OutErr("Unable to get contents of %s\n", SymName); if (hr == S_OK) { sprintf(SymName, "%s!iPass", GDIKM_Module.Name); hr = ReadSymbolData(Client, SymName, &iPass, sizeof(iPass), NULL); if (hr != S_OK) OutCtl.OutErr("Unable to get contents of %s\n", SymName); } if (hr == S_OK) { sprintf(SymName, "%s!argnlog", GDIKM_Module.Name); hr = GetArrayDimensions(Client, SymName, NULL, &LogArraySize, &LogLength, &LogEntrySize); if (hr != S_OK) OutCtl.OutErr("Unable to get dimensions of %s\n", SymName); } if (hr == S_OK) { } if (hr == S_OK) { if (*SearchStringList != '\0') { OutCtl.Output("Searching last %ld entries for:\n", DumpCount.I32); for (SearchString = SearchStringList; *SearchString != '\0'; *SearchString += strlen(SearchString)+1) { OutCtl.Output(" \"%s\"\n", SearchString); } } else { OutCtl.Output("Dumping last %ld entries.\n", DumpCount.I32); } // To Do } } } if (SearchStringList != EmptySearchString) { HeapFree(GetProcessHeap(), 0, SearchStringList); } return hr; #else dprintf("Extension 'rgnlog' is not converted.\n"); #if ENABLE_OLD_EXTS // DOES NOT SUPPORT API64 LONG cDump; LONG iCurrent; RGNLOGENTRY rl; RGNLOGENTRY *prl; LONG gml; // gMaxRgnLog int i, j; PVOID pv; CHAR achTmp[30]; CHAR achBuf[256]; PCHAR pchS[MAXSEARCH]; int cSearch; BOOL bPrint; PARSE_ARGUMENTS(rgnlog_help); if(ntok<1) { goto rgnlog_help; } tok_pos = parse_FindNonSwitch(tokens, ntok); if(tok_pos==-1) { goto rgnlog_help; } //check that this supports decimal cDump = (LONG)GetExpression(tokens[tok_pos]); if(cDump==0) { goto rgnlog_help; } cSearch = 0; while(cSearch gml) cDump = gml; if (cDump > iCurrent) iCurrent += gml; iCurrent -= cDump; dprintf("prl = %lx, gml = %ld, cDump = %ld, iCurrent = %ld\n",prl,gml,cDump,iCurrent); //CHECKLOOP add exit/more support for (i = 0; i < cDump; ++i) { move(rl,&prl[iCurrent]); if (rl.pszOperation != NULL) { move2(achTmp,rl.pszOperation,30); } else achTmp[0] = 0; sprintf(achBuf,"%5lx-%4ld:%p,%p,(%8lx),%p, %p,%p, %s, %p, %p\n", (ULONG_PTR)rl.teb >> 12,iCurrent,rl.hrgn,rl.prgn,rl.lRes,rl.lParm1, rl.lParm2,rl.lParm3,achTmp,rl.pvCaller,rl.pvCallersCaller); bPrint = (cSearch == 0); for (j = 0; (j < cSearch) && !bPrint; ++j) bPrint |= bStrInStr(achBuf,pchS[j]); if (bPrint) { dprintf(achBuf); } if (++iCurrent >= gml) iCurrent = 0; if (CheckControlC()) return; } return; rgnlog_help: dprintf("\n rgnlog nnn [search1] [search2] [search3] [search4]\n"); dprintf("\t nnn - dumps the last n entries of the rgn log\n"); dprintf("\t search[n] - displays only entries containing one of n strings\n"); dprintf("\t NOTE: only works on checked builds. you must set bLogRgn at run time\n"); #endif // DOES NOT SUPPORT API64 EXIT_API(S_OK); #endif }