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
598 lines
18 KiB
/*++
|
|
|
|
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 [-?] <Entries> [<Search Strings>]\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<MAXSEARCH) {
|
|
tok_pos = parse_FindNonSwitch(tokens, ntok, tok_pos+1);
|
|
if(tok_pos==-1) {break;}
|
|
pchS[cSearch]=tokens[tok_pos];
|
|
cSearch++;
|
|
}
|
|
|
|
for (i = 0; i < cSearch; ++i)
|
|
dprintf("search[%s]\n",pchS[i]);
|
|
|
|
// get some stuff
|
|
|
|
GetAddress(pv, "&win32k!iLog");
|
|
|
|
dprintf("&iLog = %lx\n",pv);
|
|
|
|
if (pv == NULL)
|
|
{
|
|
dprintf("iCurrent was NULL\n");
|
|
return;
|
|
}
|
|
move(iCurrent, pv);
|
|
|
|
GetAddress(i,"&win32k!iPass");
|
|
|
|
if (pv == NULL)
|
|
{
|
|
dprintf("iPass was NULL\n");
|
|
return;
|
|
}
|
|
move(i,i);
|
|
|
|
dprintf("--------------------------------------------------\n");
|
|
dprintf("rgn log list, cDump = %ld, iCur = %ld, iPass = %ld\n", cDump,iCurrent,i);
|
|
dprintf("%5s-%4s:%8s,%8s,(%8s),%8s,%8s,%4s\n",
|
|
"TEB ","i","hrgn","prgn","return","arg1","arg2","arg3");
|
|
dprintf("--------------------------------------------------\n");
|
|
|
|
// Dereference the handle via the engine's handle manager.
|
|
|
|
GetAddress(prl, "win32k!argnlog");
|
|
|
|
if (!prl)
|
|
{
|
|
dprintf("prl was NULL\n");
|
|
return;
|
|
}
|
|
|
|
GetAddress(gml, "&win32k!gMaxRgnLog");
|
|
|
|
if (!gml)
|
|
{
|
|
dprintf("gml was NULL\n");
|
|
return;
|
|
}
|
|
move(gml,gml);
|
|
|
|
// set iCurrent to the first thing to dump
|
|
|
|
if (cDump > 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
|
|
}
|
|
|
|
|
|
|
|
|