windows-nt/Source/XPSP1/NT/net/1394/arp/kdext/parse.c
2020-09-26 16:20:57 +08:00

1742 lines
36 KiB
C

#include "common.h"
typedef struct
{
eKEYWORD eKey;
char *szzAliases; // Multi-sz string of aliases.
// First one is the "official" name.
} KEYWORDREC;
KEYWORDREC rgKeywords[] =
{
{keywordHELP, "help\0"},
// OBSOLETE {keywordDUMP_TYPE, "dt\0"},
// OBSOLETE {keywordDUMP_GLOBALS, "dg\0"},
{keywordL, "L\0"},
{keywordNULL, NULL} // sentinel, must be last.
};
//
// Contains the list of tokens created by parsing an input string.
//
typedef struct
{
TOKEN *rgToks;
UINT cToks;
UINT uNextFreeTok;
UINT uCurrentTok;
char *rgStringBuf;
UINT cchStringBuf;
UINT uNextFree;
BOOL fFinalized;
CRITICAL_SECTION crit;
} TOKLIST;
DBGCOMMAND *
parse_command(TOKLIST *pTL, NAMESPACE *pNameSpace);
TOKLIST
*toklist_create(void);
void
toklist_destroy(TOKLIST *pTL);
BOOL
toklist_add(TOKLIST *pTL, eTOKTYPE eTok, char *szOrig, UINT uID);
BOOL
toklist_finalize(TOKLIST *pTL);
TOKEN *
toklist_get_next(TOKLIST *pTL);
BOOL
toklist_restart(TOKLIST *pTL);
void
toklist_dump(TOKLIST *pTL);
void
tok_dump(TOKEN *pTok);
UINT
toklist_tokenize(TOKLIST *pTL, char *szInput);
UINT
toklist_parse_keyword(
TOKLIST *pTL,
KEYWORDREC rgKeywords[],
char *pcInput
);
UINT
toklist_parse_hexnum(
TOKLIST *pTL,
char *pcInput
);
UINT
toklist_parse_identifier(
TOKLIST *pTL,
char *pcInput
);
BOOL
cmd_parse_help(
DBGCOMMAND *pCmd,
TOKLIST *pTL
);
BOOL
tok_try_force_to_ident(TOKLIST *pTL, BOOL fPrefixStar, TOKEN *pTok);
void
MyDumpObject (
DBGCOMMAND *pCmd,
TYPE_INFO *pType,
UINT_PTR uAddr,
UINT cbSize,
const char *szDescription
);
ULONG
NodeFunc_DumpType (
UINT_PTR uNodeAddr,
UINT uIndex,
void *pvContext
);
ULONG
NodeFunc_UpdateCache (
UINT_PTR uNodeAddr,
UINT uIndex,
void *pvContext
);
DBGCOMMAND *
Parse(
IN const char *szInput,
IN NAMESPACE *pNameSpace
)
{
TOKLIST *pTL = NULL;
BOOL fRet = FALSE;
DBGCOMMAND *pCmd = NULL;
UINT cbInput = (lstrlenA(szInput)+1)*sizeof(*szInput);
char *szRWInput
= LocalAlloc(LPTR, cbInput);
// MyDbgPrintf("Parse(\"%s\");\n", szInput);
if (szRWInput)
{
CopyMemory(szRWInput, szInput, cbInput);
pTL = toklist_create();
}
if (pTL)
{
#if TEST_TOKLIST_ADD
#if 0
fRet = toklist_add(pTL, tokSTAR, "*", tokSTAR);
fRet = toklist_add(pTL, tokDOT, ".", tokDOT);
fRet = toklist_add(pTL, tokQUESTION, "?", tokQUESTION);
fRet = toklist_add(pTL, tokLBRAC, "[", tokLBRAC);
fRet = toklist_add(pTL, tokRBRAC, "]", tokRBRAC);
fRet = toklist_add(pTL, tokSLASH, "/", tokSLASH);
fRet = toklist_add(pTL, tokKEYWORD, "help", keywordHELP);
fRet = toklist_add(pTL, tokNUMBER, "0x1234", 0x1234);
fRet = toklist_add(pTL, tokIDENTIFIER, "cow", 0);
fRet = toklist_add(pTL, tokSTAR, "*", tokSTAR);
fRet = toklist_add(pTL, tokDOT, ".", tokDOT);
fRet = toklist_add(pTL, tokQUESTION, "?", tokQUESTION);
fRet = toklist_add(pTL, tokLBRAC, "[", tokLBRAC);
fRet = toklist_add(pTL, tokRBRAC, "]", tokRBRAC);
fRet = toklist_add(pTL, tokSLASH, "/", tokSLASH);
fRet = toklist_add(pTL, tokKEYWORD, "help", keywordHELP);
fRet = toklist_add(pTL, tokNUMBER, "0x1234", 0x1234);
fRet = toklist_add(pTL, tokIDENTIFIER, "cow", 0);
#else
char rgInput[] =
// "*.?[]/"
// "help "
// "0x12340 0 1 02 "
// "kelp"
"dt if[*].*handle* 0x324890 L 5"
;
toklist_tokenize (pTL, rgInput);
#endif
#endif // TEST_TOKLIST_ADD
toklist_tokenize(pTL, szRWInput);
toklist_finalize(pTL);
// toklist_dump(pTL);
pCmd = parse_command(pTL, pNameSpace);
if (!pCmd)
{
toklist_destroy(pTL);
}
pTL = NULL;
}
if (szRWInput)
{
LocalFree(szRWInput);
szRWInput = NULL;
}
return pCmd;
}
void
FreeCommand(
DBGCOMMAND *pCmd
)
{
if (pCmd)
{
TOKLIST *pTL = (TOKLIST*)pCmd->pvContext;
if (pTL)
{
// MyDbgPrintf("FreeCommand:\n");
// toklist_restart(pTL);
// toklist_dump(pTL);
toklist_destroy((TOKLIST*)pCmd->pvContext);
}
ZeroMemory(pCmd, sizeof(*pCmd));
LocalFree(pCmd);
}
}
void
DumpCommand(
DBGCOMMAND *pCmd
)
{
char *szCmd = "";
char *szObjPreStar = "";
char *szObj = "";
char *szObjSufStar = "";
char *szObjVecRange = "";
char *szDot = "";
char *szSubObjPreStar = "";
char *szSubObj = "";
char *szSubObjSufStar = "";
char *szObjAddr = "";
char *szObjCount = "";
char rgVecRange[64];
char rgObjAddr[64];
char rgObjCount[64];
if (!pCmd) goto end;
switch(pCmd->ePrimaryCmd)
{
case cmdDUMP_TYPE: szCmd = "dt"; break;
case cmdDUMP_GLOBALS: szCmd = "dg"; break;
case cmdHELP: szCmd = "help"; break;
default: szCmd = "<unknown>"; break;
}
if (CMD_IS_FLAG_SET(pCmd, fCMDFLAG_OBJECT_STAR_PREFIX))
{
szObjPreStar = "*";
}
if (pCmd->ptokObject)
{
szObj = pCmd->ptokObject->szStr;
}
if (CMD_IS_FLAG_SET(pCmd, fCMDFLAG_OBJECT_STAR_SUFFIX))
{
szObjSufStar = "*";
}
if (CMD_IS_FLAG_SET(pCmd, fCMDFLAG_HAS_VECTOR_INDEX))
{
wsprintfA(
rgVecRange,
"[%ld,%ld]",
pCmd->uVectorIndexStart,
pCmd->uVectorIndexEnd
);
szObjVecRange = rgVecRange;
}
if (CMD_IS_FLAG_SET(pCmd, fCMDFLAG_HAS_SUBOBJECT))
{
szDot = ".";
}
if (CMD_IS_FLAG_SET(pCmd, fCMDFLAG_SUBOBJECT_STAR_PREFIX))
{
szSubObjPreStar = "*";
}
if (pCmd->ptokSubObject)
{
szSubObj = pCmd->ptokSubObject->szStr;
}
if (CMD_IS_FLAG_SET(pCmd, fCMDFLAG_SUBOBJECT_STAR_SUFFIX))
{
szSubObjSufStar = "*";
}
if (CMD_IS_FLAG_SET(pCmd, fCMDFLAG_HAS_OBJECT_ADDRESS))
{
wsprintf(rgObjAddr, "0x%lx", pCmd->uObjectAddress);
szObjAddr = rgObjAddr;
}
if (CMD_IS_FLAG_SET(pCmd, fCMDFLAG_HAS_OBJECT_COUNT))
{
wsprintf(rgObjCount, " L 0x%lx", pCmd->uObjectCount);
szObjCount = rgObjCount;
}
if (0)
{
#if 0
MyDbgPrintf(
"\nCOMMAND = {"
"cmd=%lu;"
"F=0x%lx;"
"O=0x%lx;"
"SO=0x%lx;"
"VS=%ld;"
"VE=%ld;"
"OA=0x%lx;"
"OC=%ld;"
"}\n",
pCmd->ePrimaryCmd,
pCmd->uFlags,
pCmd->ptokObject,
pCmd->ptokSubObject,
pCmd->uVectorIndexStart,
pCmd->uVectorIndexEnd,
pCmd->uObjectAddress,
pCmd->uObjectCount
);
#else
MyDbgPrintf(
"COMMAND = \"%s %s%s%s%s%s%s%s%s%s%s\";\n",
szCmd,
szObjPreStar,
szObj,
szObjSufStar,
szObjVecRange,
szDot,
szSubObjPreStar,
szSubObj,
szSubObjSufStar,
szObjAddr,
szObjCount
);
#endif
}
end:
return;
}
#define TL_LOCK(_ptl) EnterCriticalSection(&(_ptl)->crit)
#define TL_UNLOCK(_ptl) LeaveCriticalSection(&(_ptl)->crit)
TOKLIST
*toklist_create(void)
{
TOKLIST *pTL = LocalAlloc(LPTR, sizeof(TOKLIST));
if (pTL)
{
InitializeCriticalSection(&pTL->crit);
}
return pTL;
}
void
toklist_destroy(TOKLIST *pTL)
{
if (pTL)
{
TL_LOCK(pTL);
if (pTL->rgToks)
{
LocalFree(pTL->rgToks);
}
if (pTL->rgStringBuf)
{
LocalFree(pTL->rgStringBuf);
}
DeleteCriticalSection(&pTL->crit);
ZeroMemory(pTL, sizeof(*pTL));
LocalFree(pTL);
}
}
BOOL
toklist_add(TOKLIST *pTL, eTOKTYPE eTok, char *szOrig, UINT uID)
{
BOOL fRet = FALSE;
TOKEN *pTok = NULL;
UINT cch = 0;
char *pc = NULL;
TL_LOCK(pTL);
if (pTL->fFinalized) goto end;
//
// Make sure we've enough space for the token.
//
if (pTL->uNextFreeTok >= pTL->cToks)
{
UINT cNewToks = 2*pTL->cToks+1;
TOKEN *pNewToks = (TOKEN*) LocalAlloc(LPTR, cNewToks*sizeof(*pNewToks));
if (!pNewToks) goto end;
if (pTL->rgToks)
{
CopyMemory(
pNewToks,
pTL->rgToks,
pTL->uNextFreeTok*sizeof(*pNewToks)
);
LocalFree(pTL->rgToks);
}
pTL->rgToks = pNewToks;
pTL->cToks = cNewToks;
}
//
// Now deal with szOrig
//
cch = lstrlenA(szOrig)+1;
if ((pTL->uNextFree+cch+1) > pTL->cchStringBuf) // "+1" because multisz
{
UINT cNewStr = 2*pTL->cchStringBuf+cch+1;
char *pNewStr = LocalAlloc(LPTR, cNewStr*sizeof(*pNewStr));
if (!pNewStr) goto end;
if (pTL->rgStringBuf)
{
CopyMemory(
pNewStr,
pTL->rgStringBuf,
pTL->uNextFree*sizeof(*pNewStr)
);
LocalFree(pTL->rgStringBuf);
//
// Since we've reallocated the string buffer, we must
// now fixup the string pointers in the list of tokens
//
{
TOKEN *pTok = pTL->rgToks;
TOKEN *pTokEnd = pTok + pTL->uNextFreeTok;
for(; pTok<pTokEnd; pTok++)
{
pTok->szStr = pNewStr + (pTok->szStr - pTL->rgStringBuf);
}
}
}
pTL->rgStringBuf = pNewStr;
pTL->cchStringBuf = cNewStr;
}
//
// At this point we know we have enough space...
//
//
// See if we already have this string and if not copy it...
//
{
BOOL fFound = FALSE;
for (pc = pTL->rgStringBuf; *pc; pc+=(lstrlenA(pc)+1))
{
if (!lstrcmpiA(pc, szOrig))
{
// found it
fFound = TRUE;
break;
}
}
if (!fFound)
{
MYASSERT(pTL->uNextFree == (UINT) (pc-pTL->rgStringBuf));
CopyMemory(
pc,
szOrig,
cch*sizeof(*szOrig)
);
pTL->uNextFree += cch;
}
}
if (eTok == tokIDENTIFIER)
{
//
// For this special case we ignore the passed-in uID and
// use instead the offset of the string in our string table.
//
uID = (UINT) (pc - pTL->rgStringBuf);
}
pTok = pTL->rgToks+pTL->uNextFreeTok++;
pTok->eTok = eTok;
pTok->uID = uID;
pTok->szStr = pc;
fRet = TRUE;
end:
TL_UNLOCK(pTL);
return fRet;
}
BOOL
toklist_finalize(TOKLIST *pTL)
{
BOOL fRet = FALSE;
TL_LOCK(pTL);
if (pTL->fFinalized) goto end;
pTL->fFinalized = TRUE;
fRet = TRUE;
end:
TL_UNLOCK(pTL);
return fRet;
}
BOOL
toklist_restart(TOKLIST *pTL)
{
BOOL fRet = FALSE;
TL_LOCK(pTL);
if (!pTL->fFinalized) goto end;
pTL->uCurrentTok = 0;
fRet = TRUE;
end:
TL_UNLOCK(pTL);
return fRet;
}
TOKEN *
toklist_get_next(TOKLIST *pTL)
{
TOKEN *pTok = NULL;
TL_LOCK(pTL);
if (!pTL->fFinalized) goto end;
if (pTL->uCurrentTok >= pTL->uNextFreeTok)
{
MYASSERT(pTL->uCurrentTok == pTL->uNextFreeTok);
goto end;
}
else
{
pTok = pTL->rgToks+pTL->uCurrentTok++;
}
end:
TL_UNLOCK(pTL);
return pTok;
}
void
toklist_dump(TOKLIST *pTL)
{
TL_LOCK(pTL);
MyDbgPrintf(
"\nTOKLIST 0x%08lx = {"
"fFin=%lu cToks=%lu uNextFreeTok=%lu cchStr=%lu uNextFree=%lu"
"}\n",
pTL,
pTL->fFinalized,
pTL->cToks,
pTL->uNextFreeTok,
pTL->cchStringBuf,
pTL->uNextFree
);
if (pTL->fFinalized)
{
TOKEN *pTok = toklist_get_next(pTL);
while(pTok)
{
tok_dump(pTok);
pTok = toklist_get_next(pTL);
}
toklist_restart(pTL);
}
TL_UNLOCK(pTL);
}
void
tok_dump(TOKEN *pTok)
{
MyDbgPrintf(
"\tTOKEN 0x%08lx = {eTok=%lu uID=0x%08lx sz=\"%s\"}\n",
pTok,
pTok->eTok,
pTok->uID,
pTok->szStr
);
}
UINT
toklist_tokenize(TOKLIST *pTL, char *szInput)
{
UINT cTokens = 0;
char *pc = szInput;
char c = 0;
BOOL fRet = FALSE;
for (; (c=*pc)!=0; pc++)
{
switch(c)
{
case '*':
fRet = toklist_add(pTL, tokSTAR, "*", tokSTAR);
continue;
case '.':
fRet = toklist_add(pTL, tokDOT, ".", tokDOT);
continue;
case '?':
fRet = toklist_add(pTL, tokQUESTION, "?", tokQUESTION);
continue;
case '[':
fRet = toklist_add(pTL, tokLBRAC, "[", tokLBRAC);
continue;
case ']':
fRet = toklist_add(pTL, tokRBRAC, "]", tokRBRAC);
continue;
case '/':
fRet = toklist_add(pTL, tokSLASH, "/", tokSLASH);
continue;
case '\n':
case '\r':
case '\t':
case ' ':
continue;
default:
{
UINT uCharsParsed = 0;
char *pcEnd = pc;
char cSave = 0;
//
// We'll locate the end of the potential keyword/number/ident:
// and temprarily place a NULL char there.
//
//
while (__iscsym(*pcEnd))
{
pcEnd++;
}
cSave = *pcEnd;
*pcEnd = 0;
if (__iscsymf(c))
{
// This may be a keyword, hex number or identifier. We try
// in this order
uCharsParsed = toklist_parse_keyword(
pTL,
rgKeywords,
pc
);
if (!uCharsParsed && isxdigit(c))
{
//
// Didn't find a keyword and this is a hex digit --
// let's try to parse it as a hex number...
//
uCharsParsed = toklist_parse_hexnum(pTL, pc);
}
if (!uCharsParsed)
{
//
// Parse it as an identifier...
//
uCharsParsed = toklist_parse_identifier(pTL, pc);
}
if (!uCharsParsed)
{
//
// This is an error
//
MyDbgPrintf("Error at %s\n", pc);
goto end;
}
}
else if (isxdigit(c))
{
uCharsParsed = toklist_parse_hexnum(pTL, pc);
}
//
// If we've parsed anything it should be ALL of the string...
//
MYASSERT(!uCharsParsed || uCharsParsed==(UINT)lstrlenA(pc));
//
// Restore the char we replaced by NULL.
//
*pcEnd = cSave;
if (!uCharsParsed)
{
//
// Syntax error
//
MyDbgPrintf("Error at %s\n", pc);
goto end;
}
else
{
pc+= (uCharsParsed-1); // "-1" because of pc++ in
// for clause above.
}
}
}
}
end:
return cTokens;
}
UINT
toklist_parse_keyword(
TOKLIST *pTL,
KEYWORDREC rgKeywords[],
char *pcInput
)
//
// Assumes 1st char is valid.
//
{
UINT uRet = 0;
KEYWORDREC *pkr = rgKeywords;
if (!__iscsymf(*pcInput)) goto end;
for (;pkr->eKey!=keywordNULL; pkr++)
{
if (!lstrcmpi(pcInput, pkr->szzAliases))
{
//
// found it
//
toklist_add(pTL, tokKEYWORD, pcInput, pkr->eKey);
uRet = lstrlenA(pcInput);
break;
}
}
end:
return uRet;
}
UINT
toklist_parse_hexnum(
TOKLIST *pTL,
char *pcInput
)
{
char *pc = pcInput;
UINT uValue = 0;
char c;
UINT u;
//
// look for and ignore the "0x" prefix...
//
if (pc[0]=='0' && (pc[1]=='x' || pc[1]=='X'))
{
pc+=2;
}
//
// Reject number if it is doesn't contain hex digits or is too large
//
for (u=0; isxdigit(*pc) && u<8; pc++,u++)
{
UINT uDigit = 0;
char c = *pc;
if (!isdigit(c))
{
// Doesn't work if c ALREADY is upcase: c = _toupper(c);
//
if (c >= 'a' && c <= 'f')
{
c = (char) _toupper(c);
}
uDigit = 10 + c - 'A';
}
else
{
uDigit = c - '0';
}
uValue = (uValue<<4)|uDigit;
}
if (!u || *pc)
{
return 0;
}
else
{
toklist_add(pTL, tokNUMBER, pcInput, uValue);
return (UINT) (pc - pcInput);
}
}
UINT
toklist_parse_identifier(
TOKLIST *pTL,
char *pcInput
)
{
UINT uRet = 0;
if (!__iscsymf(*pcInput)) goto end;
toklist_add(pTL, tokIDENTIFIER, pcInput, 0);
uRet = lstrlenA(pcInput);
end:
return uRet;
}
DBGCOMMAND *
parse_command(TOKLIST *pTL, NAMESPACE *pNameSpace)
{
BOOL fRet = FALSE;
DBGCOMMAND *pCmd = LocalAlloc(LPTR, sizeof(*pCmd));
TOKEN *pTok = NULL;
BOOL fSyntaxError = FALSE;
if (!pCmd) goto end;
toklist_restart(pTL);
pTok = toklist_get_next(pTL);
if (!pTok) goto end;
pCmd->pNameSpace = pNameSpace;
//
// Now let's step through the token list, building up our command
// information.
//
// look for help or ?
if (pTok->eTok == tokQUESTION
|| (pTok->eTok == tokKEYWORD && pTok->uID == keywordHELP))
{
pCmd->ePrimaryCmd = cmdHELP;
fRet = cmd_parse_help(pCmd, pTL);
goto end;
}
fSyntaxError = TRUE;
fRet = FALSE;
//
// Here we would look for other keywords. Currently there are none
// (dt and dg are not used anymore).
//
//
#if OBSOLETE
if (pTok->eTok == tokKEYWORD)
{
BOOL fDump = FALSE;
if (pTok->uID == keywordDUMP_TYPE)
{
pCmd->ePrimaryCmd = cmdDUMP_TYPE;
fDump = TRUE;
}
else if (pTok->uID == keywordDUMP_GLOBALS)
{
pCmd->ePrimaryCmd = cmdDUMP_GLOBALS;
fDump = TRUE;
}
...
}
#endif // OBSOLETE
pCmd->ePrimaryCmd = cmdDUMP_TYPE;
//
// Pares the form a[b].*c* d L e
//
{
BOOL fPrefixStar = FALSE;
// we look for patterns like...
//!aac <type> . <field> <address> L <count> <flags>
//!aac <type> [index] . <field> L <count> <flags>
//
//!aac i[*].*handle* 0x324890 L 5
//[*]ident[*]\[<range>\][.][*]ident[*] <number> [L <number>]
UINT uFlags; // One or more fCMDFLAG_*
TOKEN *ptokObject; // eg <type>
TOKEN *ptokSubObject; // eg <field>
UINT uVectorIndexStart; // if[0]
UINT uVectorIndexEnd; // if[0]
UINT uObjectAddress; // <address>
UINT uObjectCount; // L 10
//
// 1. Look for primary star
//
if (pTok && pTok->eTok == tokSTAR)
{
fPrefixStar = TRUE;
CMD_SET_FLAG(pCmd, fCMDFLAG_OBJECT_STAR_PREFIX);
pTok = toklist_get_next(pTL);
}
//
// 2. Look for ident
//
if (pTok && tok_try_force_to_ident(pTL, fPrefixStar, pTok))
{
//
// This will try to convert keywords and numbers to idents if
// possible.
//
pCmd->ptokObject = pTok;
pTok = toklist_get_next(pTL);
}
//
// 3. Look for suffix * for object.
//
if (pTok && pTok->eTok == tokSTAR)
{
CMD_SET_FLAG(pCmd, fCMDFLAG_OBJECT_STAR_SUFFIX);
pTok = toklist_get_next(pTL);
}
//
// 4. Look for Vector Range
//
if (pTok && pTok->eTok == tokLBRAC)
{
//
// For now, we support either a single * or a single number.
//
pTok = toklist_get_next(pTL);
if (!pTok)
{
goto end; // Error -- incomplete vector range
}
else
{
if (pTok->eTok == tokSTAR)
{
pCmd->uVectorIndexStart = 0;
pCmd->uVectorIndexEnd = (UINT) -1;
}
else if (pTok->eTok == tokNUMBER)
{
pCmd->uVectorIndexStart =
pCmd->uVectorIndexEnd = pTok->uID;
}
else
{
goto end; // failure...
}
CMD_SET_FLAG(pCmd, fCMDFLAG_HAS_VECTOR_INDEX);
pTok = toklist_get_next(pTL);
if (!pTok || pTok->eTok != tokRBRAC)
{
goto end; // failure ... expect RBRAC.
}
else
{
pTok = toklist_get_next(pTL);
}
}
}
//
// 5. Look for DOT
//
if (pTok && pTok->eTok == tokDOT)
{
fPrefixStar = FALSE;
pTok = toklist_get_next(pTL);
// We expect ([*]ident[*]|*)
//
// 1. Look for primary star
//
if (pTok && pTok->eTok == tokSTAR)
{
fPrefixStar = TRUE;
CMD_SET_FLAG(pCmd, fCMDFLAG_SUBOBJECT_STAR_PREFIX);
pTok = toklist_get_next(pTL);
}
//
// 2. Look for ident
//
if (pTok && tok_try_force_to_ident(pTL, fPrefixStar, pTok))
{
//
// This will try to convert keywords and numbers to idents if
// possible.
//
pCmd->ptokSubObject = pTok;
pTok = toklist_get_next(pTL);
}
//
// 3. Look for suffix * for object.
//
if (pTok && pTok->eTok == tokSTAR)
{
CMD_SET_FLAG(pCmd, fCMDFLAG_SUBOBJECT_STAR_SUFFIX);
pTok = toklist_get_next(pTL);
}
//
// At this point we should either have a non-null IDENT
// or the PREFIX START should be set for the object
// (indicateing "a.*").
//
if ( pCmd->ptokSubObject
|| (pCmd->uFlags & fCMDFLAG_SUBOBJECT_STAR_SUFFIX))
{
CMD_SET_FLAG(pCmd, fCMDFLAG_HAS_SUBOBJECT);
}
else
{
goto end; // error
}
}
//
// 6. Look for object address
//
if (pTok && pTok->eTok == tokNUMBER)
{
pCmd->uObjectAddress = pTok->uID;
CMD_SET_FLAG(pCmd, fCMDFLAG_HAS_OBJECT_ADDRESS);
pTok = toklist_get_next(pTL);
}
//
// 7. Look for object count
//
if ( pTok && pTok->eTok == tokKEYWORD
&& pTok->uID == keywordL)
{
pTok = toklist_get_next(pTL);
if (pTok && pTok->eTok == tokNUMBER)
{
pCmd->uObjectCount = pTok->uID;
CMD_SET_FLAG(pCmd, fCMDFLAG_HAS_OBJECT_COUNT);
pTok = toklist_get_next(pTL);
}
else
{
// error
}
}
//
// At this point we should be done...
//
if (pTok)
{
// error -- extra garbage...
}
else
{
// Success.
fRet = TRUE;
fSyntaxError = FALSE;
}
}
end:
if (fRet)
{
pCmd->pvContext = pTL;
}
else
{
if (fSyntaxError)
{
MyDbgPrintf("Unexpected: %s\n", (pTok) ? pTok->szStr : "<null>");
}
else
{
MyDbgPrintf("Parse failed\n");
}
if (pCmd)
{
ZeroMemory(pCmd, sizeof(*pCmd));
LocalFree(pCmd);
pCmd = NULL;
}
}
if (pTL)
{
toklist_restart(pTL);
}
return pCmd;
}
BOOL
cmd_parse_help(
DBGCOMMAND *pCmd,
TOKLIST *pTL
)
{
TOKEN *pTok = toklist_get_next(pTL);
if (!pTok || pTok->eTok == tokSTAR)
{
// User type "help" or "help *"
MyDbgPrintf("DO HELP\n");
}
return TRUE;
}
BOOL
tok_try_force_to_ident(TOKLIST *pTL, BOOL fPrefixStar, TOKEN *pTok)
//
// This gets called when an identifier is expected -- so we see if this
// particular token can be interpreted as in identifier. Some examples
// of when we can do this:
// dt if.*20334 <--- the "20334" could be part of an identifier, because
// of the * prefix.
//
// dt L.help <--- both "L" and "help" would have been parsed as
// keywords, but here they are intended to be
// identifiers.
// dt abc.def <--- abc and def would have been parsed as numbers (they
// are valid hex numbers), but are intended to be
// identifiers.
{
BOOL fRet = FALSE;
switch(pTok->eTok)
{
case tokNUMBER:
//
// We could do this, but subject to some restrictions...
//
if (!__iscsymf(pTok->szStr[0]) && !fPrefixStar)
{
break; // Can't to this: no prefix wild-card (*) and the
// number starts with a non-letter.
}
// FALL THROUGH ...
case tokKEYWORD:
//
// We can go ahead, but we must make pTok.uID now the offset
// from the start of the internal string array.
//
{
char *pc = pTL->rgStringBuf;
for (; *pc; pc+=(lstrlenA(pc)+1))
{
if (!lstrcmpiA(pc, pTok->szStr))
{
// found it
// MyDbgPrintf("FORCE_TO_IDENT:\nOLD:\n");
// tok_dump(pTok);
pTok->uID = (UINT) (pc - pTL->rgStringBuf);
pTok->eTok = tokIDENTIFIER;
// MyDbgPrintf("NEW:\n");
// tok_dump(pTok);
fRet = TRUE;
break;
}
}
}
break;
case tokIDENTIFIER:
//
// nothing to do...
//
fRet = TRUE;
break;
default:
//
// Can't convert any other kind of token to identifier...
//
break;
}
return fRet;
}
void
DoCommand(DBGCOMMAND *pCmd, PFN_SPECIAL_COMMAND_HANDLER pfnHandler)
{
char *szMsg = NULL;
// pCmd->pfnSpecialHandler = pfnHandler;
switch(pCmd->ePrimaryCmd)
{
case cmdDUMP_TYPE:
DoDumpType(pCmd);
break;
case cmdDUMP_GLOBALS:
DoDumpGlobals(pCmd);
break;
case cmdHELP:
DoHelp(pCmd);
break;
default:
szMsg = "Unknown command\n";
break;
}
if (szMsg)
{
MyDbgPrintf(szMsg);
}
return;
}
typedef struct
{
DBGCOMMAND *pCmd;
TYPE_INFO *pType;
} MY_LIST_NODE_CONTEXT;
typedef
ULONG
MyDumpListNode (
UINT_PTR uNodeAddr,
UINT uIndex,
void *pvContext
);
void
DoDumpType(DBGCOMMAND *pCmd)
{
char *szPattern = NULL;
PFNMATCHINGFUNCTION pfnMatchingFunction = MatchAlways;
TYPE_INFO **ppti = NULL;
UINT uMatchCount = 0;
TYPE_INFO *ptiDump = NULL;
//
// Pick a selection function ...
//
if (pCmd->ptokObject)
{
szPattern = pCmd->ptokObject->szStr;
if ( CMD_IS_FLAG_SET(pCmd, fCMDFLAG_OBJECT_STAR_PREFIX)
&&CMD_IS_FLAG_SET(pCmd, fCMDFLAG_OBJECT_STAR_SUFFIX))
{
pfnMatchingFunction = MatchSubstring;
}
else if (CMD_IS_FLAG_SET(pCmd, fCMDFLAG_OBJECT_STAR_PREFIX))
{
pfnMatchingFunction = MatchSuffix;
}
else if (CMD_IS_FLAG_SET(pCmd, fCMDFLAG_OBJECT_STAR_SUFFIX))
{
pfnMatchingFunction = MatchPrefix;
}
else
{
pfnMatchingFunction = MatchExactly;
}
}
//
// search through global type array for type pName.
//
for(ppti=pCmd->pNameSpace->pTypes;*ppti;ppti++)
{
TYPE_INFO *pti = *ppti;
bool fMatch = !szPattern
|| !_stricmp(szPattern, pti->szShortName)
|| pfnMatchingFunction(szPattern, pti->szName);
if (fMatch)
{
#if 0
MyDbgPrintf(
"TYPE \"%2s\" %s (%lu Bytes)\n",
pti->szShortName,
pti->szName,
pti->cbSize
);
#endif // 0
uMatchCount++;
if (!ptiDump)
{
ptiDump = pti;
}
#if 0
uAddr =
MyDbgPrintf(
"dc 0x%08lx L %03lx \"%2s\" %s\n",
pgi->uAddr,
pgi->cbSize,
pgi->szShortName,
pgi->szName
);
if (szPattern && pgi->uAddr)
{
MyDumpObject(
pCmd,
pgi->pBaseType,
pgi->uAddr,
pgi->cbSize,
pgi->szName
);
}
#endif // 0
}
}
if (!uMatchCount)
{
MyDbgPrintf(
"Could not find type \"%s\"",
(szPattern ? szPattern : "*")
);
}
else if ( uMatchCount==1)
{
UINT uObjectCount = 1;
UINT uStartIndex = 0;
UINT_PTR uObjectAddress = 0;
BOOLEAN fList = TYPEISLIST(ptiDump)!=0;
if (CMD_IS_FLAG_SET(pCmd, fCMDFLAG_HAS_OBJECT_ADDRESS))
{
uObjectAddress = pCmd->uObjectAddress;
}
//
// Determine start index.
//
if (CMD_IS_FLAG_SET(pCmd, fCMDFLAG_HAS_VECTOR_INDEX))
{
uStartIndex = pCmd->uVectorIndexStart;
if (fList && !CMD_IS_FLAG_SET(pCmd, fCMDFLAG_HAS_OBJECT_COUNT))
{
uObjectCount = pCmd->uVectorIndexEnd - uStartIndex;
if (uObjectCount != (UINT) -1)
{
uObjectCount++;
}
}
}
//
// Determine object count...
//
if (CMD_IS_FLAG_SET(pCmd, fCMDFLAG_HAS_OBJECT_COUNT))
{
uObjectCount = pCmd->uObjectCount;
}
//
// If no address is specified, we'll try to resolve it ...
//
if (!CMD_IS_FLAG_SET(pCmd, fCMDFLAG_HAS_OBJECT_ADDRESS))
{
BOOLEAN fUseCache = FALSE;
//
// Algorithm for determining whether to use cache or to resolve
// address:
//
if (ptiDump->uCachedAddress)
{
//
// Except for the special case of [0], we will use
// the the cached value.
//
if (!( uStartIndex ==0
&& uObjectCount==1
&& CMD_IS_FLAG_SET(pCmd, fCMDFLAG_HAS_VECTOR_INDEX)))
{
fUseCache = TRUE;
}
}
if (fUseCache)
{
uObjectAddress = ptiDump->uCachedAddress;
}
else
{
if (pCmd->pNameSpace->pfnResolveAddress)
{
uObjectAddress = pCmd->pNameSpace->pfnResolveAddress(
ptiDump
);
}
}
}
if (uObjectAddress && uObjectCount)
{
//
// Prune these to "reasonable" values.
//
if (uObjectCount > 100)
{
MyDbgPrintf("Limiting object count to 100\n");
uObjectCount = 100;
}
if (fList)
{
MY_LIST_NODE_CONTEXT Context;
Context.pCmd = pCmd;
Context.pType = ptiDump;
WalkList(
uObjectAddress, // start address
ptiDump->uNextOffset, // next offset
uStartIndex,
uStartIndex+uObjectCount-1, // end index
&Context, // context
NodeFunc_DumpType, // function
(char *) ptiDump->szName
);
//
// If only a single structure was dumped, and it was dumped
// successfully, we will update this structure's cache.
// TODO: we don't check for success
//
if (uObjectCount==1)
{
WalkList(
uObjectAddress, // start address
ptiDump->uNextOffset, // next offset
uStartIndex,
uStartIndex, // end index
ptiDump, // context
NodeFunc_UpdateCache, // function
(char *) ptiDump->szName
);
}
}
else
{
UINT cbSize = ptiDump->cbSize;
UINT_PTR uAddr = uObjectAddress + uStartIndex*cbSize;
UINT_PTR uEnd = uAddr + uObjectCount*cbSize;
//
// For arays, compute offset to start address
//
uObjectAddress = uAddr;
for (; uAddr<uEnd; uAddr+=cbSize)
{
MyDumpObject(
pCmd,
ptiDump,
uAddr,
ptiDump->cbSize,
ptiDump->szName
);
}
//
// If only a single structure was dumped, and it was dumped
// successfully, we will update this structure's cache.
// TODO: we don't check for success
//
if (uObjectCount==1)
{
ptiDump->uCachedAddress = uObjectAddress;
}
}
}
else
{
MyDbgPrintf(
"Could not resolve address for object %s\n",
ptiDump->szName
);
}
}
}
void
DoDumpGlobals(DBGCOMMAND *pCmd)
{
GLOBALVAR_INFO *pgi = pCmd->pNameSpace->pGlobals;
char *szPattern = NULL;
PFNMATCHINGFUNCTION pfnMatchingFunction = MatchAlways;
//
// Pick a selection function ...
//
if (pCmd->ptokObject)
{
szPattern = pCmd->ptokObject->szStr;
if ( CMD_IS_FLAG_SET(pCmd, fCMDFLAG_OBJECT_STAR_PREFIX)
&&CMD_IS_FLAG_SET(pCmd, fCMDFLAG_OBJECT_STAR_SUFFIX))
{
pfnMatchingFunction = MatchSubstring;
}
else if (CMD_IS_FLAG_SET(pCmd, fCMDFLAG_OBJECT_STAR_PREFIX))
{
pfnMatchingFunction = MatchSuffix;
}
else if (CMD_IS_FLAG_SET(pCmd, fCMDFLAG_OBJECT_STAR_SUFFIX))
{
pfnMatchingFunction = MatchPrefix;
}
else
{
pfnMatchingFunction = MatchExactly;
}
}
//
// Run through our list of globals, and if the entry is selected,
// we will display it.
//
for (;pgi->szName; pgi++)
{
bool fMatch = !szPattern
|| !_stricmp(szPattern, pgi->szShortName)
|| pfnMatchingFunction(szPattern, pgi->szName);
if (fMatch)
{
pgi->uAddr = dbgextGetExpression(pgi->szName);
MyDbgPrintf(
"dc 0x%08lx L %03lx \"%2s\" %s\n",
pgi->uAddr,
pgi->cbSize,
pgi->szShortName,
pgi->szName
);
if (szPattern && pgi->uAddr)
{
MyDumpObject(
pCmd,
pgi->pBaseType,
pgi->uAddr,
pgi->cbSize,
pgi->szName
);
}
}
}
}
void
DoHelp(
DBGCOMMAND *pCmd // OPTIONAL
)
{
//
//
//
MyDbgPrintf("help unimplemented\n");
}
void
MyDumpObject (
DBGCOMMAND *pCmd,
TYPE_INFO *pType,
UINT_PTR uAddr,
UINT cbSize,
const char *szDescription
)
{
UINT uMatchFlags = 0;
char *szFieldSpec = NULL;
if (pCmd->ptokSubObject)
{
szFieldSpec = pCmd->ptokSubObject->szStr;
if ( CMD_IS_FLAG_SET(pCmd, fCMDFLAG_SUBOBJECT_STAR_PREFIX)
&&CMD_IS_FLAG_SET(pCmd, fCMDFLAG_SUBOBJECT_STAR_SUFFIX))
{
uMatchFlags = fMATCH_SUBSTRING;
}
else if (CMD_IS_FLAG_SET(pCmd, fCMDFLAG_SUBOBJECT_STAR_PREFIX))
{
uMatchFlags = fMATCH_SUFFIX;
}
else if (CMD_IS_FLAG_SET(pCmd, fCMDFLAG_SUBOBJECT_STAR_SUFFIX))
{
uMatchFlags = fMATCH_PREFIX;
}
}
if (!pType)
{
DumpMemory(
uAddr,
cbSize,
0,
szDescription
);
}
else
{
DumpStructure(pType, uAddr, szFieldSpec, uMatchFlags);
}
}
ULONG
NodeFunc_DumpType (
UINT_PTR uNodeAddr,
UINT uIndex,
void *pvContext
)
{
MY_LIST_NODE_CONTEXT *pContext = (MY_LIST_NODE_CONTEXT*) pvContext;
MyDbgPrintf("[%lu] ", uIndex);
MyDumpObject (
pContext->pCmd,
pContext->pType,
uNodeAddr,
pContext->pType->cbSize,
pContext->pType->szName
);
return 0;
}
ULONG
NodeFunc_UpdateCache (
UINT_PTR uNodeAddr,
UINT uIndex,
void *pvContext
)
{
TYPE_INFO *pti = (TYPE_INFO*) pvContext;
if (pti->uCachedAddress != uNodeAddr)
{
MyDbgPrintf(
"Updating Cache from 0x%lx to 0x%lx\n",
pti->uCachedAddress,
uNodeAddr
);
}
pti->uCachedAddress = uNodeAddr;
return 0;
}