1538 lines
42 KiB
C
1538 lines
42 KiB
C
|
/*** ntexpr.c - expression evaluator for NT debugger
|
|||
|
*
|
|||
|
* Copyright <C> 1990, Microsoft Corporation
|
|||
|
*
|
|||
|
* Purpose:
|
|||
|
* With the current command line at *pchCommand, parse
|
|||
|
* and evaluate the next expression.
|
|||
|
*
|
|||
|
* Revision History:
|
|||
|
*
|
|||
|
* [-] 18-Apr-1990 Richk Created - split from ntcmd.c.
|
|||
|
*
|
|||
|
*************************************************************************/
|
|||
|
|
|||
|
#include <string.h>
|
|||
|
|
|||
|
#include "ntsdp.h"
|
|||
|
#ifdef i386
|
|||
|
#include <nti386.h>
|
|||
|
#include "86reg.h"
|
|||
|
#endif
|
|||
|
|
|||
|
ULONG PeekToken(PLONG);
|
|||
|
ULONG GetTokenSym(PLONG);
|
|||
|
ULONG NextToken(PLONG);
|
|||
|
void AcceptToken(void);
|
|||
|
UCHAR PeekChar(void);
|
|||
|
|
|||
|
ULONG GetExpression(void);
|
|||
|
BOOLEAN GetLocalFromString(PUCHAR, PULONG);
|
|||
|
ULONG GetCommonExpression(VOID);
|
|||
|
void GetLowerString(PUCHAR, ULONG);
|
|||
|
LONG GetExpr(void);
|
|||
|
LONG GetLRterm(void);
|
|||
|
LONG GetLterm(void);
|
|||
|
LONG GetAterm(void);
|
|||
|
LONG GetMterm(void);
|
|||
|
LONG GetTerm(void);
|
|||
|
USHORT addrExpression;
|
|||
|
ADDR tempAddr;
|
|||
|
|
|||
|
#ifdef KERNEL
|
|||
|
extern USHORT DefaultProcessor;
|
|||
|
#endif
|
|||
|
|
|||
|
/////
|
|||
|
BOOLEAN SymbolOnlyExpr(void);
|
|||
|
/////
|
|||
|
|
|||
|
struct Res {
|
|||
|
UCHAR chRes[3];
|
|||
|
ULONG classRes;
|
|||
|
ULONG valueRes;
|
|||
|
} Reserved[] = {
|
|||
|
{ 'o', 'r', '\0', LOGOP_CLASS, LOGOP_OR },
|
|||
|
{ 'b', 'y', '\0', UNOP_CLASS, UNOP_BY },
|
|||
|
{ 'w', 'o', '\0', UNOP_CLASS, UNOP_WO },
|
|||
|
{ 'd', 'w', '\0', UNOP_CLASS, UNOP_DW },
|
|||
|
{ 'h', 'i', '\0', UNOP_CLASS, UNOP_HI },
|
|||
|
{ 'm', 'o', 'd', MULOP_CLASS, MULOP_MOD },
|
|||
|
{ 'x', 'o', 'r', LOGOP_CLASS, LOGOP_XOR },
|
|||
|
{ 'a', 'n', 'd', LOGOP_CLASS, LOGOP_AND },
|
|||
|
{ 'p', 'o', 'i', UNOP_CLASS, UNOP_POI },
|
|||
|
{ 'n', 'o', 't', UNOP_CLASS, UNOP_NOT },
|
|||
|
{ 'l', 'o', 'w', UNOP_CLASS, UNOP_LOW }
|
|||
|
#ifdef i386
|
|||
|
,{ 'e', 'a', 'x', REG_CLASS, REGEAX },
|
|||
|
{ 'e', 'b', 'x', REG_CLASS, REGEBX },
|
|||
|
{ 'e', 'c', 'x', REG_CLASS, REGECX },
|
|||
|
{ 'e', 'd', 'x', REG_CLASS, REGEDX },
|
|||
|
{ 'e', 'b', 'p', REG_CLASS, REGEBP },
|
|||
|
{ 'e', 's', 'p', REG_CLASS, REGESP },
|
|||
|
{ 'e', 'i', 'p', REG_CLASS, REGEIP },
|
|||
|
{ 'e', 's', 'i', REG_CLASS, REGESI },
|
|||
|
{ 'e', 'd', 'i', REG_CLASS, REGEDI },
|
|||
|
{ 'e', 'f', 'l', REG_CLASS, REGEFL }
|
|||
|
#endif
|
|||
|
};
|
|||
|
|
|||
|
#define RESERVESIZE (sizeof(Reserved) / sizeof(struct Res))
|
|||
|
|
|||
|
ULONG savedClass;
|
|||
|
LONG savedValue;
|
|||
|
UCHAR *savedpchCmd;
|
|||
|
|
|||
|
ULONG EXPRLastExpression = 0;
|
|||
|
extern BOOLEAN fPhysicalAddress;
|
|||
|
extern int fControlC;
|
|||
|
#ifdef KERNEL
|
|||
|
extern void cdecl _loadds ControlCHandler(void);
|
|||
|
#endif
|
|||
|
extern BOOL cdecl cmdHandler(ULONG);
|
|||
|
extern BOOL cdecl waitHandler(ULONG);
|
|||
|
|
|||
|
/*** GetExpression - read and evaluate expression (top-level)
|
|||
|
*
|
|||
|
* Purpose:
|
|||
|
* From the current command line position at pchCommand,
|
|||
|
* read and evaluate the next possible expression and
|
|||
|
* return its value. The expression is parsed and evaluated
|
|||
|
* using a recursive descent method.
|
|||
|
*
|
|||
|
* Input:
|
|||
|
* pchCommand - command line position
|
|||
|
*
|
|||
|
* Returns:
|
|||
|
* unsigned long value of expression.
|
|||
|
*
|
|||
|
* Exceptions:
|
|||
|
* error exit: SYNTAX - empty expression or premature end-of-line
|
|||
|
*
|
|||
|
* Notes:
|
|||
|
* the routine will attempt to parse the longest expression
|
|||
|
* possible.
|
|||
|
*
|
|||
|
*************************************************************************/
|
|||
|
|
|||
|
ULONG GetExpression (void)
|
|||
|
{
|
|||
|
ULONG value;
|
|||
|
|
|||
|
value = GetCommonExpression();
|
|||
|
|
|||
|
EXPRLastExpression = value;
|
|||
|
return value;
|
|||
|
}
|
|||
|
|
|||
|
/*** GetAddrExpression - read and evaluate address expression
|
|||
|
*
|
|||
|
* Purpose:
|
|||
|
* Used to get an address expression.
|
|||
|
*
|
|||
|
* Returns:
|
|||
|
* Pointer to address packet
|
|||
|
*
|
|||
|
* Exceptions:
|
|||
|
* error exit: SYNTAX - empty expression or premature end-of-line
|
|||
|
*
|
|||
|
*
|
|||
|
*************************************************************************/
|
|||
|
PADDR GetAddrExpression (ULONG defaultSeg, PADDR Address)
|
|||
|
{
|
|||
|
ULONG value;
|
|||
|
|
|||
|
NotFlat(*Address);
|
|||
|
|
|||
|
// Do a normal GetExpression call
|
|||
|
|
|||
|
value = GetExpression();
|
|||
|
*Address = tempAddr;
|
|||
|
|
|||
|
// If it wasn't an explicit address expression
|
|||
|
// force it to be an address
|
|||
|
|
|||
|
if (!(addrExpression & ~INSTR_POINTER)) {
|
|||
|
Off(*Address) = value;
|
|||
|
|
|||
|
#ifdef i386
|
|||
|
addrExpression = Address->type =
|
|||
|
fVm86 ? ADDR_V86 : (f16pm ? ADDR_16 : ADDR_32);
|
|||
|
if ((addrExpression != ADDR_32) && defaultSeg != -1L)
|
|||
|
Address->seg = (USHORT)GetRegValue(defaultSeg);
|
|||
|
#else
|
|||
|
addrExpression = Address->type = ADDR_32;
|
|||
|
#endif
|
|||
|
ComputeFlatAddress(Address, NULL);
|
|||
|
|
|||
|
} else if fnotFlat(*Address) {
|
|||
|
|
|||
|
// This case (i.e., addrExpression && !flat) results from
|
|||
|
// an override (i.e., %,,&, or #) being used but no segment
|
|||
|
// being specified to force a flat address computation.
|
|||
|
|
|||
|
Type(*Address)= addrExpression;
|
|||
|
Off(*Address) = value;
|
|||
|
#ifdef i386
|
|||
|
if (defaultSeg == -1L)
|
|||
|
Address->seg = 0;
|
|||
|
else {
|
|||
|
|
|||
|
// test flag for IP or EIP as register argument
|
|||
|
// if so, use CS as default register
|
|||
|
|
|||
|
if (fInstrPtr(*Address))
|
|||
|
defaultSeg = REGCS;
|
|||
|
Address->seg = (USHORT)GetRegValue(defaultSeg);
|
|||
|
}
|
|||
|
#endif
|
|||
|
ComputeFlatAddress(Address, NULL);
|
|||
|
}
|
|||
|
|
|||
|
return Address;
|
|||
|
}
|
|||
|
|
|||
|
/*** GetCommonExpression - read and evaluate expression
|
|||
|
*
|
|||
|
* Purpose:
|
|||
|
* From the current command line position at pchCommand,
|
|||
|
* read and evaluate the next possible expression.
|
|||
|
* return either its value if a memory expression, or
|
|||
|
* its symbol file and line number structures if a source
|
|||
|
* line expression.
|
|||
|
*
|
|||
|
* Input:
|
|||
|
* pchCommand - command line position
|
|||
|
*
|
|||
|
* Outputs:
|
|||
|
* *ppSymfile - nonNULL for symbol file structure
|
|||
|
* NULL for returning memory offset
|
|||
|
* *ppLineno - lineno structure
|
|||
|
* fSourceDefault - treat '.' as line number if TRUE
|
|||
|
* else as program counter value in GetExpr.
|
|||
|
*
|
|||
|
* Returns:
|
|||
|
* if (*ppSymfile) - line number (USHORT)
|
|||
|
* if (!*ppSymfile) - ULONG value of expression.
|
|||
|
* Exceptions:
|
|||
|
* error exit: SYNTAX - empty expression or premature end-of-line
|
|||
|
*
|
|||
|
* Notes:
|
|||
|
* parsing for source line expressions is done here. the syntax is:
|
|||
|
*
|
|||
|
* [<module>! [<file>[.<expr>]]]
|
|||
|
*
|
|||
|
* if no <module> and/or <file> is/are specified, the current
|
|||
|
* program counter is used to determine the defaults.
|
|||
|
* if '.' is used, <expr> evaluates to a line number, else
|
|||
|
* a memory address is calculated. NO WHITE SPACE BETWEEN
|
|||
|
* '.' AND <expr>.
|
|||
|
*
|
|||
|
*************************************************************************/
|
|||
|
|
|||
|
ULONG
|
|||
|
GetCommonExpression(
|
|||
|
VOID
|
|||
|
)
|
|||
|
{
|
|||
|
PUCHAR pchCommandSaved;
|
|||
|
UCHAR chModule[40];
|
|||
|
UCHAR chFilename[40];
|
|||
|
UCHAR ch;
|
|||
|
ULONG value;
|
|||
|
PIMAGE_INFO pImage;
|
|||
|
ULONG baseSaved;
|
|||
|
PUCHAR pchFilename;
|
|||
|
|
|||
|
savedClass = (ULONG)-1;
|
|||
|
pchCommandSaved = pchCommand;
|
|||
|
|
|||
|
if (PeekChar() == '!')
|
|||
|
pchCommand++;
|
|||
|
|
|||
|
GetLowerString(chModule, 40);
|
|||
|
ch = PeekChar();
|
|||
|
|
|||
|
// if '!' is next, chModule has <module>, chFilename has <file>
|
|||
|
// else copy chFilename to chModule and set chModule to NULL
|
|||
|
|
|||
|
if (ch == '!') {
|
|||
|
pchCommand++;
|
|||
|
GetLowerString(chFilename, 40);
|
|||
|
ch = PeekChar();
|
|||
|
}
|
|||
|
else {
|
|||
|
strcpy(chFilename, chModule);
|
|||
|
chModule[0] = '\0';
|
|||
|
}
|
|||
|
|
|||
|
pchCommand = pchCommandSaved;
|
|||
|
|
|||
|
ch = PeekChar();
|
|||
|
// Change this switch statement to a x?y:z type expression
|
|||
|
switch(ch) {
|
|||
|
case '&':
|
|||
|
pchCommand++;
|
|||
|
addrExpression = ADDR_V86;
|
|||
|
break;
|
|||
|
case '#':
|
|||
|
pchCommand++;
|
|||
|
addrExpression = ADDR_16;
|
|||
|
break;
|
|||
|
case '%':
|
|||
|
pchCommand++;
|
|||
|
addrExpression = ADDR_32;
|
|||
|
break;
|
|||
|
default:
|
|||
|
addrExpression = FALSE;
|
|||
|
break;
|
|||
|
}
|
|||
|
ch = PeekChar();
|
|||
|
value = (ULONG)GetExpr();
|
|||
|
|
|||
|
return value;
|
|||
|
}
|
|||
|
|
|||
|
void GetLowerString (PUCHAR pchBuffer, ULONG cbBuffer)
|
|||
|
{
|
|||
|
UCHAR ch;
|
|||
|
|
|||
|
ch = PeekChar();
|
|||
|
ch = (UCHAR)tolower(ch);
|
|||
|
while ((ch == '_' || (ch >= 'a' && ch <= 'z')
|
|||
|
|| (ch >= '0' && ch <= '9')) && --cbBuffer) {
|
|||
|
*pchBuffer++ = ch;
|
|||
|
ch = *++pchCommand;
|
|||
|
}
|
|||
|
*pchBuffer = '\0';
|
|||
|
}
|
|||
|
|
|||
|
/*** GetExpr - Get expression
|
|||
|
*
|
|||
|
* Purpose:
|
|||
|
* Parse logical-terms separated by logical operators into
|
|||
|
* expression value.
|
|||
|
*
|
|||
|
* Input:
|
|||
|
* pchCommand - present command line position
|
|||
|
*
|
|||
|
* Returns:
|
|||
|
* long value of logical result.
|
|||
|
*
|
|||
|
* Exceptions:
|
|||
|
* error exit: SYNTAX - bad expression or premature end-of-line
|
|||
|
*
|
|||
|
* Notes:
|
|||
|
* may be called recursively.
|
|||
|
* <expr> = <lterm> [<logic-op> <lterm>]*
|
|||
|
* <logic-op> = AND (&), OR (|), XOR (^)
|
|||
|
*
|
|||
|
*************************************************************************/
|
|||
|
|
|||
|
LONG GetExpr ()
|
|||
|
{
|
|||
|
LONG value1;
|
|||
|
LONG value2;
|
|||
|
ULONG opclass;
|
|||
|
LONG opvalue;
|
|||
|
|
|||
|
//dprintf("LONG GetExpr ()\n");
|
|||
|
value1 = GetLRterm();
|
|||
|
while ((opclass = PeekToken(&opvalue)) == LOGOP_CLASS) {
|
|||
|
AcceptToken();
|
|||
|
value2 = GetLRterm();
|
|||
|
switch (opvalue) {
|
|||
|
case LOGOP_AND:
|
|||
|
value1 &= value2;
|
|||
|
break;
|
|||
|
case LOGOP_OR:
|
|||
|
value1 |= value2;
|
|||
|
break;
|
|||
|
case LOGOP_XOR:
|
|||
|
value1 ^= value2;
|
|||
|
break;
|
|||
|
default:
|
|||
|
error(SYNTAX);
|
|||
|
}
|
|||
|
}
|
|||
|
return value1;
|
|||
|
}
|
|||
|
|
|||
|
/*** GetLRterm - get logical relational term
|
|||
|
*
|
|||
|
* Purpose:
|
|||
|
* Parse logical-terms separated by logical relational
|
|||
|
* operators into the expression value.
|
|||
|
*
|
|||
|
* Input:
|
|||
|
* pchCommand - present command line position
|
|||
|
*
|
|||
|
* Returns:
|
|||
|
* long value of logical result.
|
|||
|
*
|
|||
|
* Exceptions:
|
|||
|
* error exit: SYNTAX - bad expression or premature end-of-line
|
|||
|
*
|
|||
|
* Notes:
|
|||
|
* may be called recursively.
|
|||
|
* <expr> = <lterm> [<rel-logic-op> <lterm>]*
|
|||
|
* <logic-op> = '==' or '=', '!=', '>', '<'
|
|||
|
*
|
|||
|
*************************************************************************/
|
|||
|
|
|||
|
LONG GetLRterm ()
|
|||
|
{
|
|||
|
LONG value1;
|
|||
|
LONG value2;
|
|||
|
ULONG opclass;
|
|||
|
LONG opvalue;
|
|||
|
|
|||
|
//dprintf("LONG GetLRterm ()\n");
|
|||
|
value1 = GetLterm();
|
|||
|
while ((opclass = PeekToken(&opvalue)) == LRELOP_CLASS) {
|
|||
|
AcceptToken();
|
|||
|
value2 = GetLterm();
|
|||
|
switch (opvalue) {
|
|||
|
case LRELOP_EQ:
|
|||
|
value1 = (value1 == value2);
|
|||
|
break;
|
|||
|
case LRELOP_NE:
|
|||
|
value1 = (value1 != value2);
|
|||
|
break;
|
|||
|
case LRELOP_LT:
|
|||
|
value1 = (value1 < value2);
|
|||
|
break;
|
|||
|
case LRELOP_GT:
|
|||
|
value1 = (value1 > value2);
|
|||
|
break;
|
|||
|
default:
|
|||
|
error(SYNTAX);
|
|||
|
}
|
|||
|
}
|
|||
|
return value1;
|
|||
|
}
|
|||
|
|
|||
|
/*** GetLterm - get logical term
|
|||
|
*
|
|||
|
* Purpose:
|
|||
|
* Parse additive-terms separated by additive operators into
|
|||
|
* logical term value.
|
|||
|
*
|
|||
|
* Input:
|
|||
|
* pchCommand - present command line position
|
|||
|
*
|
|||
|
* Returns:
|
|||
|
* long value of sum.
|
|||
|
*
|
|||
|
* Exceptions:
|
|||
|
* error exit: SYNTAX - bad logical term or premature end-of-line
|
|||
|
*
|
|||
|
* Notes:
|
|||
|
* may be called recursively.
|
|||
|
* <lterm> = <aterm> [<add-op> <aterm>]*
|
|||
|
* <add-op> = +, -
|
|||
|
*
|
|||
|
*************************************************************************/
|
|||
|
|
|||
|
LONG GetLterm ()
|
|||
|
{
|
|||
|
LONG value1 = GetAterm();
|
|||
|
LONG value2;
|
|||
|
ULONG opclass;
|
|||
|
LONG opvalue;
|
|||
|
BOOLEAN faddr = (BOOLEAN) addrExpression;
|
|||
|
|
|||
|
//dprintf("LONG GetLterm ()\n");
|
|||
|
while ((opclass = PeekToken(&opvalue)) == ADDOP_CLASS) {
|
|||
|
AcceptToken();
|
|||
|
value2 = GetAterm();
|
|||
|
if (!faddr && addrExpression) {
|
|||
|
LONG tmp = value1;
|
|||
|
value1 = value2;
|
|||
|
value2 = tmp;
|
|||
|
}
|
|||
|
#ifndef i386
|
|||
|
if (addrExpression) {
|
|||
|
#else
|
|||
|
if (addrExpression & ~INSTR_POINTER) {
|
|||
|
#endif
|
|||
|
switch (opvalue) {
|
|||
|
case ADDOP_PLUS:
|
|||
|
AddrAdd(&tempAddr,value2);
|
|||
|
value1 += value2;
|
|||
|
break;
|
|||
|
case ADDOP_MINUS:
|
|||
|
AddrSub(&tempAddr,value2);
|
|||
|
value1 -= value2;
|
|||
|
break;
|
|||
|
default:
|
|||
|
error(SYNTAX);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
switch (opvalue) {
|
|||
|
case ADDOP_PLUS:
|
|||
|
value1 += value2;
|
|||
|
break;
|
|||
|
case ADDOP_MINUS:
|
|||
|
value1 -= value2;
|
|||
|
break;
|
|||
|
default:
|
|||
|
error(SYNTAX);
|
|||
|
}
|
|||
|
}
|
|||
|
return value1;
|
|||
|
}
|
|||
|
|
|||
|
/*** GetAterm - get additive term
|
|||
|
*
|
|||
|
* Purpose:
|
|||
|
* Parse multiplicative-terms separated by multipicative operators
|
|||
|
* into additive term value.
|
|||
|
*
|
|||
|
* Input:
|
|||
|
* pchCommand - present command line position
|
|||
|
*
|
|||
|
* Returns:
|
|||
|
* long value of product.
|
|||
|
*
|
|||
|
* Exceptions:
|
|||
|
* error exit: SYNTAX - bad additive term or premature end-of-line
|
|||
|
*
|
|||
|
* Notes:
|
|||
|
* may be called recursively.
|
|||
|
* <aterm> = <mterm> [<mult-op> <mterm>]*
|
|||
|
* <mult-op> = *, /, MOD (%)
|
|||
|
*
|
|||
|
*************************************************************************/
|
|||
|
|
|||
|
LONG GetAterm ()
|
|||
|
{
|
|||
|
LONG value1;
|
|||
|
LONG value2;
|
|||
|
ULONG opclass;
|
|||
|
LONG opvalue;
|
|||
|
|
|||
|
//dprintf("LONG GetAterm ()\n");
|
|||
|
value1 = GetMterm();
|
|||
|
while ((opclass = PeekToken(&opvalue)) == MULOP_CLASS) {
|
|||
|
AcceptToken();
|
|||
|
value2 = GetAterm();
|
|||
|
switch (opvalue) {
|
|||
|
case MULOP_MULT:
|
|||
|
value1 *= value2;
|
|||
|
break;
|
|||
|
case MULOP_DIVIDE:
|
|||
|
value1 /= value2;
|
|||
|
break;
|
|||
|
case MULOP_MOD:
|
|||
|
value1 %= value2;
|
|||
|
break;
|
|||
|
case MULOP_SEG:{
|
|||
|
PDESCRIPTOR_TABLE_ENTRY pdesc=NULL;
|
|||
|
|
|||
|
if (!addrExpression) {
|
|||
|
// We don't know what kind of address this is
|
|||
|
// Let's try to figure it out.
|
|||
|
#ifdef i386
|
|||
|
if (fVm86) addrExpression = Type(tempAddr) = ADDR_V86;
|
|||
|
else {
|
|||
|
DESCRIPTOR_TABLE_ENTRY desc;
|
|||
|
desc.Selector = value1;
|
|||
|
if (DbgKdLookupSelector(DefaultProcessor, &desc)
|
|||
|
!=STATUS_SUCCESS) error(BADSEG);
|
|||
|
addrExpression = Type(tempAddr) =
|
|||
|
(UCHAR)desc.Descriptor.HighWord.
|
|||
|
Bits.Default_Big? ADDR_1632:ADDR_16;
|
|||
|
pdesc = &desc;
|
|||
|
}
|
|||
|
#else
|
|||
|
addrExpression = Type(tempAddr) = ADDR_32;
|
|||
|
#endif
|
|||
|
}
|
|||
|
else
|
|||
|
Type(tempAddr) = addrExpression;
|
|||
|
|
|||
|
tempAddr.seg = (USHORT)value1;
|
|||
|
tempAddr.off = value2;
|
|||
|
ComputeFlatAddress(&tempAddr, pdesc);
|
|||
|
value1 = value2;
|
|||
|
}
|
|||
|
break;
|
|||
|
default:
|
|||
|
error(SYNTAX);
|
|||
|
}
|
|||
|
}
|
|||
|
return value1;
|
|||
|
}
|
|||
|
|
|||
|
/*** GetMterm - get multiplicative term
|
|||
|
*
|
|||
|
* Purpose:
|
|||
|
* Parse basic-terms optionally prefaced by one or more
|
|||
|
* unary operators into a multiplicative term.
|
|||
|
*
|
|||
|
* Input:
|
|||
|
* pchCommand - present command line position
|
|||
|
*
|
|||
|
* Returns:
|
|||
|
* long value of multiplicative term.
|
|||
|
*
|
|||
|
* Exceptions:
|
|||
|
* error exit: SYNTAX - bad multiplicative term or premature end-of-line
|
|||
|
*
|
|||
|
* Notes:
|
|||
|
* may be called recursively.
|
|||
|
* <mterm> = [<unary-op>] <term> | <unary-op> <mterm>
|
|||
|
* <unary-op> = <add-op>, ~ (NOT), BY, WO, DW, HI, LOW
|
|||
|
*
|
|||
|
*************************************************************************/
|
|||
|
|
|||
|
LONG GetMterm ()
|
|||
|
{
|
|||
|
LONG value;
|
|||
|
USHORT wvalue;
|
|||
|
UCHAR bvalue;
|
|||
|
ULONG opclass;
|
|||
|
LONG opvalue;
|
|||
|
|
|||
|
//dprintf("LONG GetMterm ()\n");
|
|||
|
if ((opclass = PeekToken(&opvalue)) == UNOP_CLASS ||
|
|||
|
opclass == ADDOP_CLASS) {
|
|||
|
AcceptToken();
|
|||
|
value = GetMterm();
|
|||
|
switch (opvalue) {
|
|||
|
case UNOP_NOT:
|
|||
|
value = !value;
|
|||
|
break;
|
|||
|
case UNOP_BY:
|
|||
|
case UNOP_WO:
|
|||
|
case UNOP_DW:
|
|||
|
case UNOP_POI:
|
|||
|
|
|||
|
NotFlat(tempAddr);
|
|||
|
|
|||
|
Off(tempAddr) = value;
|
|||
|
Type(tempAddr) = ADDR_32;
|
|||
|
|
|||
|
ComputeFlatAddress(&tempAddr, NULL);
|
|||
|
|
|||
|
switch (opvalue) {
|
|||
|
case UNOP_BY:
|
|||
|
if (!GetMemByte(&tempAddr, &bvalue))
|
|||
|
error(MEMORY);
|
|||
|
value = (LONG)bvalue;
|
|||
|
break;
|
|||
|
case UNOP_WO:
|
|||
|
if (!GetMemWord(&tempAddr, &wvalue))
|
|||
|
error(MEMORY);
|
|||
|
value = (LONG)wvalue;
|
|||
|
break;
|
|||
|
case UNOP_DW:
|
|||
|
if (!GetMemDword(&tempAddr, (PULONG)&value))
|
|||
|
error(MEMORY);
|
|||
|
break;
|
|||
|
case UNOP_POI:
|
|||
|
//
|
|||
|
// There should be some special processing for
|
|||
|
// 16:16 or 16:32 addresses (i.e. take the DWORD)
|
|||
|
// and make it back into a value with a possible
|
|||
|
// segment, but I've left this for others who might
|
|||
|
// know more of what they want.
|
|||
|
//
|
|||
|
if (!GetMemDword(&tempAddr, (PULONG)&value))
|
|||
|
error(MEMORY);
|
|||
|
break;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case UNOP_LOW:
|
|||
|
value &= 0xffff;
|
|||
|
break;
|
|||
|
case UNOP_HI:
|
|||
|
(ULONG)value >>= 16;
|
|||
|
break;
|
|||
|
case ADDOP_PLUS:
|
|||
|
break;
|
|||
|
case ADDOP_MINUS:
|
|||
|
value = -value;
|
|||
|
break;
|
|||
|
default:
|
|||
|
error(SYNTAX);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
value = GetTerm();
|
|||
|
return value;
|
|||
|
}
|
|||
|
|
|||
|
/*** GetTerm - get basic term
|
|||
|
*
|
|||
|
* Purpose:
|
|||
|
* Parse numeric, variable, or register name into a basic
|
|||
|
* term value.
|
|||
|
*
|
|||
|
* Input:
|
|||
|
* pchCommand - present command line position
|
|||
|
*
|
|||
|
* Returns:
|
|||
|
* long value of basic term.
|
|||
|
*
|
|||
|
* Exceptions:
|
|||
|
* error exit: SYNTAX - empty basic term or premature end-of-line
|
|||
|
*
|
|||
|
* Notes:
|
|||
|
* may be called recursively.
|
|||
|
* <term> = ( <expr> ) | <register-value> | <number> | <variable>
|
|||
|
* <register-value> = @<register-name>
|
|||
|
*
|
|||
|
*************************************************************************/
|
|||
|
|
|||
|
LONG GetTerm ()
|
|||
|
{
|
|||
|
LONG value;
|
|||
|
ULONG opclass;
|
|||
|
LONG opvalue;
|
|||
|
|
|||
|
//dprintf("LONG GetTerm ()\n");
|
|||
|
opclass = GetTokenSym(&opvalue);
|
|||
|
if (opclass == LPAREN_CLASS) {
|
|||
|
value = GetExpr();
|
|||
|
if (GetTokenSym(&opvalue) != RPAREN_CLASS)
|
|||
|
error(SYNTAX);
|
|||
|
}
|
|||
|
else if (opclass == REG_CLASS) {
|
|||
|
#ifdef i386
|
|||
|
if (opvalue == REGEIP || opvalue == REGIP) {
|
|||
|
addrExpression |= INSTR_POINTER;
|
|||
|
}
|
|||
|
#endif
|
|||
|
value = (ULONG)GetRegFlagValue(opvalue);
|
|||
|
}
|
|||
|
else if (opclass == NUMBER_CLASS || opclass == SYMBOL_CLASS) {
|
|||
|
value = opvalue;
|
|||
|
}
|
|||
|
else {
|
|||
|
error(SYNTAX);
|
|||
|
}
|
|||
|
|
|||
|
return value;
|
|||
|
}
|
|||
|
|
|||
|
/*** GetRange - parse address range specification
|
|||
|
*
|
|||
|
* Purpose:
|
|||
|
* With the current command line position, parse an
|
|||
|
* address range specification. Forms accepted are:
|
|||
|
* <start-addr> - starting address with default length
|
|||
|
* <start-addr> <end-addr> - inclusive address range
|
|||
|
* <start-addr> l<count> - starting address with item count
|
|||
|
*
|
|||
|
* Input:
|
|||
|
* pchCommand - present command line location
|
|||
|
* size - nonzero - (for data) size in bytes of items to list
|
|||
|
* specification will be "length" type with
|
|||
|
* *fLength forced to TRUE.
|
|||
|
* zero - (for instructions) specification either "length"
|
|||
|
* or "range" type, no size assumption made.
|
|||
|
*
|
|||
|
* Output:
|
|||
|
* *addr - starting address of range
|
|||
|
* *value - if *fLength = TRUE, count of items (forced if size != 0)
|
|||
|
* FALSE, ending address of range
|
|||
|
* (*addr and *value unchanged if no second argument in command)
|
|||
|
*
|
|||
|
* Exceptions:
|
|||
|
* error exit:
|
|||
|
* SYNTAX - expression error
|
|||
|
* BADRANGE - if ending address before starting address
|
|||
|
*
|
|||
|
*************************************************************************/
|
|||
|
|
|||
|
void GetRange (PADDR addr, PULONG value, PBOOLEAN fLength, ULONG size
|
|||
|
#ifdef i386
|
|||
|
,ULONG defaultSeg
|
|||
|
#endif
|
|||
|
)
|
|||
|
|
|||
|
{
|
|||
|
#ifndef i386
|
|||
|
ULONG defaultSeg = 0;
|
|||
|
#endif
|
|||
|
UCHAR ch;
|
|||
|
PUCHAR psz;
|
|||
|
static ADDR EndRange;
|
|||
|
BOOLEAN fSpace = FALSE;
|
|||
|
BOOLEAN fL = FALSE;
|
|||
|
|
|||
|
PeekChar(); // skip leading whitespace first
|
|||
|
|
|||
|
// Pre-parse the line, look for a " L"
|
|||
|
|
|||
|
for (psz = pchCommand; *psz; psz++) {
|
|||
|
if ((*psz == 'L' || *psz == 'l') && fSpace) {
|
|||
|
fL = TRUE;
|
|||
|
*psz = '\0';
|
|||
|
break;
|
|||
|
}
|
|||
|
fSpace = (BOOLEAN)(*psz == ' ');
|
|||
|
}
|
|||
|
|
|||
|
if ((ch = PeekChar()) != '\0' && ch != ';') {
|
|||
|
GetAddrExpression(defaultSeg, addr);
|
|||
|
if (((ch = PeekChar()) != '\0' && ch != ';') || fL) {
|
|||
|
// if ((ch = PeekChar()) == 'L' || ch == 'l') {
|
|||
|
// pchCommand++;
|
|||
|
// *fLength = TRUE;
|
|||
|
// }
|
|||
|
if (!fL) {
|
|||
|
GetAddrExpression(defaultSeg, &EndRange);
|
|||
|
*value = (ULONG)&EndRange;
|
|||
|
if (AddrGt(*addr,EndRange))
|
|||
|
error(BADRANGE);
|
|||
|
if (size) {
|
|||
|
*value = AddrDiff(EndRange, *addr) / size + 1;
|
|||
|
*fLength = TRUE;
|
|||
|
}
|
|||
|
else
|
|||
|
*fLength = FALSE;
|
|||
|
return;
|
|||
|
}
|
|||
|
else {
|
|||
|
*fLength = TRUE;
|
|||
|
pchCommand = psz + 1;
|
|||
|
*value = GetExpression();
|
|||
|
*psz = 'l';
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// if (size){
|
|||
|
// *value = AddrDiff((PADDR)*value, addr) / size + 1;
|
|||
|
// *fLength = TRUE;
|
|||
|
// }
|
|||
|
}
|
|||
|
|
|||
|
/*** PeekChar - peek the next non-white-space character
|
|||
|
*
|
|||
|
* Purpose:
|
|||
|
* Return the next non-white-space character and update
|
|||
|
* pchCommand to point to it.
|
|||
|
*
|
|||
|
* Input:
|
|||
|
* pchCommand - present command line position.
|
|||
|
*
|
|||
|
* Returns:
|
|||
|
* next non-white-space character
|
|||
|
*
|
|||
|
*************************************************************************/
|
|||
|
|
|||
|
UCHAR PeekChar (void)
|
|||
|
{
|
|||
|
UCHAR ch;
|
|||
|
|
|||
|
//dprintf("UCHAR PeekChar (void)\n");
|
|||
|
do
|
|||
|
ch = *pchCommand++;
|
|||
|
while (ch == ' ' || ch == '\t');
|
|||
|
pchCommand--;
|
|||
|
return ch;
|
|||
|
}
|
|||
|
|
|||
|
/*** PeekToken - peek the next command line token
|
|||
|
*
|
|||
|
* Purpose:
|
|||
|
* Return the next command line token, but do not advance
|
|||
|
* the pchCommand pointer.
|
|||
|
*
|
|||
|
* Input:
|
|||
|
* pchCommand - present command line position.
|
|||
|
*
|
|||
|
* Output:
|
|||
|
* *pvalue - optional value of token
|
|||
|
* Returns:
|
|||
|
* class of token
|
|||
|
*
|
|||
|
* Notes:
|
|||
|
* savedClass, savedValue, and savedpchCmd saves the token getting
|
|||
|
* state for future peeks. To get the next token, a GetToken or
|
|||
|
* AcceptToken call must first be made.
|
|||
|
*
|
|||
|
*************************************************************************/
|
|||
|
|
|||
|
ULONG PeekToken (PLONG pvalue)
|
|||
|
{
|
|||
|
UCHAR *pchTemp;
|
|||
|
|
|||
|
//dprintf("ULONG PeekToken (PLONG pvalue)\n");
|
|||
|
// Get next class and value, but do not
|
|||
|
// move pchCommand, but save it in savedpchCmd.
|
|||
|
// Do not report any error condition.
|
|||
|
|
|||
|
if (savedClass == -1) {
|
|||
|
pchTemp = pchCommand;
|
|||
|
savedClass = NextToken(&savedValue);
|
|||
|
savedpchCmd = pchCommand;
|
|||
|
pchCommand = pchTemp;
|
|||
|
}
|
|||
|
*pvalue = savedValue;
|
|||
|
return savedClass;
|
|||
|
}
|
|||
|
|
|||
|
/*** AcceptToken - accept any peeked token
|
|||
|
*
|
|||
|
* Purpose:
|
|||
|
* To reset the PeekToken saved variables so the next PeekToken
|
|||
|
* will get the next token in the command line.
|
|||
|
*
|
|||
|
* Input:
|
|||
|
* None.
|
|||
|
*
|
|||
|
* Output:
|
|||
|
* None.
|
|||
|
*
|
|||
|
*************************************************************************/
|
|||
|
|
|||
|
void AcceptToken (void)
|
|||
|
{
|
|||
|
//dprintf("void AcceptToken (void)\n");
|
|||
|
savedClass = (ULONG)-1;
|
|||
|
pchCommand = savedpchCmd;
|
|||
|
}
|
|||
|
|
|||
|
/*** GetToken - peek and accept the next token
|
|||
|
*
|
|||
|
* Purpose:
|
|||
|
* Combines the functionality of PeekToken and AcceptToken
|
|||
|
* to return the class and optional value of the next token
|
|||
|
* as well as updating the command pointer pchCommand.
|
|||
|
*
|
|||
|
* Input:
|
|||
|
* pchCommand - present command string pointer
|
|||
|
*
|
|||
|
* Output:
|
|||
|
* *pvalue - pointer to the token value optionally set.
|
|||
|
* Returns:
|
|||
|
* class of the token read.
|
|||
|
*
|
|||
|
* Notes:
|
|||
|
* An illegal token returns the value of ERROR_CLASS with *pvalue
|
|||
|
* being the error number, but produces no actual error.
|
|||
|
*
|
|||
|
*************************************************************************/
|
|||
|
|
|||
|
ULONG
|
|||
|
GetTokenSym (
|
|||
|
PLONG pvalue
|
|||
|
)
|
|||
|
{
|
|||
|
ULONG opclass;
|
|||
|
|
|||
|
//dprintf("ULONG GetTokenSym (PLONG pvalue)\n");
|
|||
|
if (savedClass != (ULONG)-1) {
|
|||
|
opclass = savedClass;
|
|||
|
savedClass = (ULONG)-1;
|
|||
|
*pvalue = savedValue;
|
|||
|
pchCommand = savedpchCmd;
|
|||
|
}
|
|||
|
else {
|
|||
|
opclass = NextToken(pvalue);
|
|||
|
}
|
|||
|
|
|||
|
if (opclass == ERROR_CLASS) {
|
|||
|
error(*pvalue);
|
|||
|
}
|
|||
|
|
|||
|
return opclass;
|
|||
|
}
|
|||
|
|
|||
|
/*** NextToken - process the next token
|
|||
|
*
|
|||
|
* Purpose:
|
|||
|
* Parse the next token from the present command string.
|
|||
|
* After skipping any leading white space, first check for
|
|||
|
* any single character tokens or register variables. If
|
|||
|
* no match, then parse for a number or variable. If a
|
|||
|
* possible variable, check the reserved word list for operators.
|
|||
|
*
|
|||
|
* Input:
|
|||
|
* pchCommand - pointer to present command string
|
|||
|
*
|
|||
|
* Output:
|
|||
|
* *pvalue - optional value of token returned
|
|||
|
* pchCommand - updated to point past processed token
|
|||
|
* Returns:
|
|||
|
* class of token returned
|
|||
|
*
|
|||
|
* Notes:
|
|||
|
* An illegal token returns the value of ERROR_CLASS with *pvalue
|
|||
|
* being the error number, but produces no actual error.
|
|||
|
*
|
|||
|
*************************************************************************/
|
|||
|
|
|||
|
ULONG
|
|||
|
NextToken (
|
|||
|
PLONG pvalue
|
|||
|
)
|
|||
|
{
|
|||
|
ULONG base;
|
|||
|
UCHAR chSymbol[SYMBOLSIZE];
|
|||
|
UCHAR chSymbolString[SYMBOLSIZE];
|
|||
|
UCHAR chPreSym[9];
|
|||
|
ULONG cbSymbol = 0;
|
|||
|
BOOLEAN fNumber = TRUE;
|
|||
|
BOOLEAN fSymbol = TRUE;
|
|||
|
BOOLEAN fForceReg = FALSE;
|
|||
|
BOOLEAN fForceSym = FALSE;
|
|||
|
ULONG errNumber = 0;
|
|||
|
UCHAR ch;
|
|||
|
UCHAR chlow;
|
|||
|
UCHAR chtemp;
|
|||
|
UCHAR limit1 = '9';
|
|||
|
UCHAR limit2 = '9';
|
|||
|
BOOLEAN fDigit = FALSE;
|
|||
|
ULONG value = 0;
|
|||
|
ULONG tmpvalue;
|
|||
|
ULONG index;
|
|||
|
PIMAGE_INFO pImage;
|
|||
|
PUCHAR pchCmdSave;
|
|||
|
IMAGEHLP_MODULE mi;
|
|||
|
BOOL UseDeferred;
|
|||
|
|
|||
|
|
|||
|
base = baseDefault;
|
|||
|
|
|||
|
// skip leading white space.
|
|||
|
|
|||
|
do {
|
|||
|
ch = *pchCommand++;
|
|||
|
} while (ch == ' ' || ch == '\t');
|
|||
|
|
|||
|
chlow = (UCHAR)tolower(ch);
|
|||
|
|
|||
|
// test for special character operators and register variable
|
|||
|
|
|||
|
switch (chlow) {
|
|||
|
case '\0':
|
|||
|
case ';':
|
|||
|
pchCommand--;
|
|||
|
return EOL_CLASS;
|
|||
|
case '+':
|
|||
|
*pvalue = ADDOP_PLUS;
|
|||
|
return ADDOP_CLASS;
|
|||
|
case '-':
|
|||
|
*pvalue = ADDOP_MINUS;
|
|||
|
return ADDOP_CLASS;
|
|||
|
case '*':
|
|||
|
*pvalue = MULOP_MULT;
|
|||
|
return MULOP_CLASS;
|
|||
|
case '/':
|
|||
|
*pvalue = MULOP_DIVIDE;
|
|||
|
return MULOP_CLASS;
|
|||
|
case '%':
|
|||
|
*pvalue = MULOP_MOD;
|
|||
|
return MULOP_CLASS;
|
|||
|
case '&':
|
|||
|
*pvalue = LOGOP_AND;
|
|||
|
return LOGOP_CLASS;
|
|||
|
case '|':
|
|||
|
*pvalue = LOGOP_OR;
|
|||
|
return LOGOP_CLASS;
|
|||
|
case '^':
|
|||
|
*pvalue = LOGOP_XOR;
|
|||
|
return LOGOP_CLASS;
|
|||
|
case '=':
|
|||
|
if (*pchCommand == '=') {
|
|||
|
pchCommand++;
|
|||
|
}
|
|||
|
*pvalue = LRELOP_EQ;
|
|||
|
return LRELOP_CLASS;
|
|||
|
case '>':
|
|||
|
*pvalue = LRELOP_GT;
|
|||
|
return LRELOP_CLASS;
|
|||
|
case '<':
|
|||
|
*pvalue = LRELOP_LT;
|
|||
|
return LRELOP_CLASS;
|
|||
|
case '!':
|
|||
|
if (*pchCommand != '=')
|
|||
|
break;
|
|||
|
pchCommand++;
|
|||
|
*pvalue = LRELOP_NE;
|
|||
|
return LRELOP_CLASS;
|
|||
|
case '~':
|
|||
|
*pvalue = UNOP_NOT;
|
|||
|
return UNOP_CLASS;
|
|||
|
case '(':
|
|||
|
return LPAREN_CLASS;
|
|||
|
case ')':
|
|||
|
return RPAREN_CLASS;
|
|||
|
case '[':
|
|||
|
return LBRACK_CLASS;
|
|||
|
case ']':
|
|||
|
return RBRACK_CLASS;
|
|||
|
case '.':
|
|||
|
#ifdef _PPC_
|
|||
|
// Modified to test for .# to all .symbol (added if{}break; IBMCDB
|
|||
|
if (*(pchCommand + 1) >= '0' && *(pchCommand + 1) <= '9') {
|
|||
|
#endif
|
|||
|
GetRegPCValue(&tempAddr);
|
|||
|
*pvalue = Flat(tempAddr);
|
|||
|
addrExpression = Type(tempAddr);
|
|||
|
return NUMBER_CLASS;
|
|||
|
#ifdef _PPC_
|
|||
|
} else {
|
|||
|
fForceSym = TRUE;
|
|||
|
fForceReg = FALSE;
|
|||
|
fNumber = FALSE;
|
|||
|
break;
|
|||
|
}
|
|||
|
#endif
|
|||
|
case ':':
|
|||
|
*pvalue = MULOP_SEG;
|
|||
|
return MULOP_CLASS;
|
|||
|
}
|
|||
|
|
|||
|
// special prefixes - '@' for register - '!' for symbol
|
|||
|
|
|||
|
#ifndef _PPC_
|
|||
|
if (chlow == '@' || chlow == '!')
|
|||
|
#else
|
|||
|
if (chlow == '@' || chlow == '!' ||
|
|||
|
(chlow == '.' && *(pchCommand+1) == '.'))
|
|||
|
#endif
|
|||
|
{ // CDB
|
|||
|
fForceReg = (BOOLEAN)(chlow == '@');
|
|||
|
fForceSym = (BOOLEAN)!fForceReg;
|
|||
|
fNumber = FALSE;
|
|||
|
ch = *pchCommand++;
|
|||
|
chlow = (UCHAR)tolower(ch);
|
|||
|
}
|
|||
|
|
|||
|
// if string is followed by '!', but not '!=',
|
|||
|
// then it is a module name and treat as text
|
|||
|
|
|||
|
pchCmdSave = pchCommand;
|
|||
|
|
|||
|
while ((chlow >= 'a' && chlow <= 'z') ||
|
|||
|
(chlow >= '0' && chlow <= '9') ||
|
|||
|
#if !defined(_PPC_)
|
|||
|
(chlow == '_') || (chlow == '$'))
|
|||
|
#else
|
|||
|
(chlow == '_') || (chlow == '$') || (chlow == '.'))
|
|||
|
#endif
|
|||
|
{
|
|||
|
chlow = (UCHAR)tolower(*pchCommand); pchCommand++;
|
|||
|
}
|
|||
|
|
|||
|
// treat as symbol if a nonnull string is followed by '!',
|
|||
|
// but not '!='
|
|||
|
|
|||
|
if (chlow == '!' && *pchCommand != '=' && pchCmdSave != pchCommand) {
|
|||
|
fNumber = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
pchCommand = pchCmdSave;
|
|||
|
chlow = (UCHAR)tolower(ch); // ch was NOT modified
|
|||
|
|
|||
|
|
|||
|
if (fNumber) {
|
|||
|
if (chlow == '\'') {
|
|||
|
*pvalue = 0;
|
|||
|
while (TRUE) {
|
|||
|
ch = *pchCommand++;
|
|||
|
if (!ch) {
|
|||
|
*pvalue = SYNTAX;
|
|||
|
return ERROR_CLASS;
|
|||
|
}
|
|||
|
if (ch == '\'') {
|
|||
|
if (*pchCommand != '\'') {
|
|||
|
break;
|
|||
|
}
|
|||
|
ch = *pchCommand++;
|
|||
|
}
|
|||
|
else
|
|||
|
if (ch == '\\') {
|
|||
|
ch = *pchCommand++;
|
|||
|
}
|
|||
|
*pvalue = (*pvalue << 8) | ch;
|
|||
|
}
|
|||
|
|
|||
|
return NUMBER_CLASS;
|
|||
|
}
|
|||
|
|
|||
|
// if first character is a decimal digit, it cannot
|
|||
|
// be a symbol. leading '0' implies octal, except
|
|||
|
// a leading '0x' implies hexadecimal.
|
|||
|
|
|||
|
if (chlow >= '0' && chlow <= '9') {
|
|||
|
if (fForceReg) {
|
|||
|
*pvalue = SYNTAX;
|
|||
|
return ERROR_CLASS;
|
|||
|
}
|
|||
|
fSymbol = FALSE;
|
|||
|
if (chlow == '0') {
|
|||
|
ch = *pchCommand++;
|
|||
|
chlow = (UCHAR)tolower(ch);
|
|||
|
if (chlow == 'x') {
|
|||
|
base = 16;
|
|||
|
ch = *pchCommand++;
|
|||
|
chlow = (UCHAR)tolower(ch);
|
|||
|
fDigit = TRUE;
|
|||
|
}
|
|||
|
else if (chlow == 'n') {
|
|||
|
base = 10;
|
|||
|
ch = *pchCommand++;
|
|||
|
chlow = (UCHAR)tolower(ch);
|
|||
|
}
|
|||
|
else {
|
|||
|
base = 8;
|
|||
|
fDigit = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// a number can start with a letter only if base is
|
|||
|
// hexadecimal and it is a hexadecimal digit 'a'-'f'.
|
|||
|
|
|||
|
else if ((chlow < 'a' || chlow > 'f') || base != 16) {
|
|||
|
fNumber = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
// set limit characters for the appropriate base.
|
|||
|
|
|||
|
if (base == 8) {
|
|||
|
limit1 = '7';
|
|||
|
}
|
|||
|
if (base == 16) {
|
|||
|
limit2 = 'f';
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// perform processing while character is a letter,
|
|||
|
// digit, underscore, or dollar-sign.
|
|||
|
|
|||
|
while ((chlow >= 'a' && chlow <= 'z') ||
|
|||
|
(chlow >= '0' && chlow <= '9') ||
|
|||
|
#if !defined(_PPC_)
|
|||
|
(chlow == '_') || (chlow == '$'))
|
|||
|
#else
|
|||
|
(chlow == '_') || (chlow == '$') || (chlow == '.'))
|
|||
|
#endif
|
|||
|
{ //IBMCDB
|
|||
|
// if possible number, test if within proper range,
|
|||
|
// and if so, accumulate sum.
|
|||
|
|
|||
|
if (fNumber) {
|
|||
|
if ((chlow >= '0' && chlow <= limit1) ||
|
|||
|
(chlow >= 'a' && chlow <= limit2)) {
|
|||
|
fDigit = TRUE;
|
|||
|
tmpvalue = value * base;
|
|||
|
if (tmpvalue < value) {
|
|||
|
errNumber = OVERFLOW;
|
|||
|
}
|
|||
|
chtemp = (UCHAR)(chlow - '0');
|
|||
|
if (chtemp > 9) {
|
|||
|
chtemp -= 'a' - '0' - 10;
|
|||
|
}
|
|||
|
value = tmpvalue + (ULONG)chtemp;
|
|||
|
if (value < tmpvalue) {
|
|||
|
errNumber = OVERFLOW;
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
fNumber = FALSE;
|
|||
|
errNumber = SYNTAX;
|
|||
|
}
|
|||
|
}
|
|||
|
if (fSymbol) {
|
|||
|
if (cbSymbol < 9) {
|
|||
|
chPreSym[cbSymbol] = chlow;
|
|||
|
}
|
|||
|
if (cbSymbol < SYMBOLSIZE - 1) {
|
|||
|
chSymbol[cbSymbol++] = ch;
|
|||
|
}
|
|||
|
}
|
|||
|
ch = *pchCommand++;
|
|||
|
chlow = (UCHAR)tolower(ch);
|
|||
|
}
|
|||
|
|
|||
|
// back up pointer to first character after token.
|
|||
|
|
|||
|
pchCommand--;
|
|||
|
|
|||
|
if (cbSymbol < 9) {
|
|||
|
chPreSym[cbSymbol] = '\0';
|
|||
|
}
|
|||
|
|
|||
|
// if fForceReg, check for register name and return
|
|||
|
// success or failure
|
|||
|
|
|||
|
if (fForceReg) {
|
|||
|
if ((*pvalue = GetRegString(chPreSym)) != -1) {
|
|||
|
return REG_CLASS;
|
|||
|
} else {
|
|||
|
*pvalue = BADREG;
|
|||
|
return ERROR_CLASS;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// test if number
|
|||
|
|
|||
|
if (fNumber && !errNumber && fDigit) {
|
|||
|
*pvalue = value;
|
|||
|
return NUMBER_CLASS;
|
|||
|
}
|
|||
|
|
|||
|
// next test for reserved word and symbol string
|
|||
|
|
|||
|
if (fSymbol && !fForceReg) {
|
|||
|
|
|||
|
// check lowercase string in chPreSym for text operator
|
|||
|
// or register name.
|
|||
|
// otherwise, return symbol value from name in chSymbol.
|
|||
|
|
|||
|
if (!fForceSym && (cbSymbol == 2 || cbSymbol == 3)) {
|
|||
|
for (index = 0; index < RESERVESIZE; index++) {
|
|||
|
if (!strncmp(chPreSym, Reserved[index].chRes, 3)) {
|
|||
|
*pvalue = Reserved[index].valueRes;
|
|||
|
return Reserved[index].classRes;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// start processing string as symbol
|
|||
|
|
|||
|
chSymbol[cbSymbol] = '\0';
|
|||
|
|
|||
|
#if defined(KERNEL)
|
|||
|
SetConsoleCtrlHandler( waitHandler, FALSE );
|
|||
|
SetConsoleCtrlHandler( cmdHandler, TRUE);
|
|||
|
#endif
|
|||
|
// test if symbol is a module name (followed by '!')
|
|||
|
// if so, get next token and treat as symbol
|
|||
|
|
|||
|
if (PeekChar() == '!') {
|
|||
|
// chSymbolString holds the name of the symbol to be searched.
|
|||
|
// chSymbol holds the symbol image file name.
|
|||
|
|
|||
|
pchCommand++;
|
|||
|
ch = PeekChar();
|
|||
|
pchCommand++;
|
|||
|
cbSymbol = 0;
|
|||
|
while ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') ||
|
|||
|
#if !defined(_PPC_)
|
|||
|
(ch >= '0' && ch <= '9') || (ch == '_') || (ch == '$'))
|
|||
|
#else
|
|||
|
(ch >= '0' && ch <= '9') || (ch == '_') || (ch == '$') ||
|
|||
|
(ch == '.'))
|
|||
|
#endif
|
|||
|
{ // IBMCDB
|
|||
|
chSymbolString[cbSymbol++] = ch;
|
|||
|
ch = *pchCommand++;
|
|||
|
}
|
|||
|
chSymbolString[cbSymbol] = '\0';
|
|||
|
pchCommand--;
|
|||
|
|
|||
|
if (cbSymbol == 0) {
|
|||
|
*pvalue = SYNTAX;
|
|||
|
return( ERROR_CLASS );
|
|||
|
}
|
|||
|
|
|||
|
strcat( chSymbol, "!" );
|
|||
|
strcat( chSymbol, chSymbolString );
|
|||
|
|
|||
|
if (GetOffsetFromSym( chSymbol, &value, 0 )) {
|
|||
|
*pvalue = value;
|
|||
|
Type(tempAddr) = ADDR_32 | FLAT_COMPUTED;
|
|||
|
Flat(tempAddr) = Off(tempAddr) = value;
|
|||
|
addrExpression = Type(tempAddr);
|
|||
|
return SYMBOL_CLASS;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
int loaded = 0;
|
|||
|
int instance = 0;
|
|||
|
ULONG insValue = 0;
|
|||
|
|
|||
|
if (cbSymbol == 0) {
|
|||
|
*pvalue = SYNTAX;
|
|||
|
return( ERROR_CLASS );
|
|||
|
}
|
|||
|
|
|||
|
for (UseDeferred=0; UseDeferred<2; UseDeferred++) {
|
|||
|
for (pImage = pProcessCurrent->pImageHead; pImage; pImage = pImage->pImageNext) {
|
|||
|
|
|||
|
if (fControlC) {
|
|||
|
fControlC = 0;
|
|||
|
*pvalue = SYNTAX;
|
|||
|
return ERROR_CLASS;
|
|||
|
}
|
|||
|
|
|||
|
if (SymGetModuleInfo( pProcessCurrent->hProcess, (ULONG)pImage->lpBaseOfImage, &mi )) {
|
|||
|
if ((mi.SymType == SymDeferred && UseDeferred) || mi.SymType != SymDeferred) {
|
|||
|
sprintf( chSymbolString, "%s!%s", mi.ModuleName, chSymbol );
|
|||
|
if (GetOffsetFromSym( chSymbolString, &value, 0 )) {
|
|||
|
//
|
|||
|
// found the symbol
|
|||
|
//
|
|||
|
*pvalue = value;
|
|||
|
instance++;
|
|||
|
insValue = *pvalue;
|
|||
|
Type(tempAddr) = ADDR_32 | FLAT_COMPUTED;
|
|||
|
Flat(tempAddr) = Off(tempAddr) = *pvalue;
|
|||
|
addrExpression = Type(tempAddr);
|
|||
|
return SYMBOL_CLASS;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// If we didn't find it, then error out if only 1 character!
|
|||
|
//
|
|||
|
if ( strlen(chSymbol) == 1 ) {
|
|||
|
*pvalue = SYMTOOSMALL;
|
|||
|
return( ERROR_CLASS );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Quick test for register names too
|
|||
|
//
|
|||
|
if (!fForceSym && (*pvalue = GetRegString(chPreSym)) != -1) {
|
|||
|
return REG_CLASS;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If there was only one instance of the symbol then return it
|
|||
|
//
|
|||
|
if (instance == 1) {
|
|||
|
*pvalue = insValue;
|
|||
|
Flat(tempAddr) = Off(tempAddr) = *pvalue;
|
|||
|
Type(tempAddr) = ADDR_32 | FLAT_COMPUTED;
|
|||
|
addrExpression= Type(tempAddr);
|
|||
|
return SYMBOL_CLASS;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If multiple instances then enumerate them for the user
|
|||
|
//
|
|||
|
if (instance) {
|
|||
|
if (fControlC) {
|
|||
|
fControlC = 0;
|
|||
|
*pvalue = SYNTAX;
|
|||
|
return ERROR_CLASS;
|
|||
|
}
|
|||
|
for (pImage=pProcessCurrent->pImageHead; pImage; pImage = pImage->pImageNext) {
|
|||
|
ULONG disp;
|
|||
|
if (SymGetSymFromAddr( pProcessCurrent->hProcess, (ULONG)*pvalue, &disp, sym )) {
|
|||
|
dprintf("%17s!%s\n", pImage->szModuleName, sym->Name );
|
|||
|
}
|
|||
|
}
|
|||
|
*pvalue = AMBIGUOUS;
|
|||
|
return ERROR_CLASS;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// symbol is undefined.
|
|||
|
// if a possible hex number, do not set the error type
|
|||
|
//
|
|||
|
if (!fNumber) {
|
|||
|
errNumber = VARDEF;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// last chance, undefined symbol and illegal number,
|
|||
|
// so test for register, will handle old format
|
|||
|
//
|
|||
|
if (!fForceSym && (*pvalue = GetRegString(chPreSym)) != -1) {
|
|||
|
return REG_CLASS;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// no success, so set error message and return
|
|||
|
//
|
|||
|
*pvalue = (ULONG)errNumber;
|
|||
|
return ERROR_CLASS;
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
SymbolOnlyExpr (
|
|||
|
VOID
|
|||
|
)
|
|||
|
{
|
|||
|
PUCHAR pchComSaved = pchCommand;
|
|||
|
LONG pvalue;
|
|||
|
ULONG class;
|
|||
|
BOOLEAN fResult;
|
|||
|
|
|||
|
//dprintf("BOOLEAN SymbolOnlyExpr (void)\n");
|
|||
|
fResult = (BOOLEAN)(NextToken(&pvalue) == SYMBOL_CLASS &&
|
|||
|
(class = NextToken(&pvalue)) != ADDOP_CLASS &&
|
|||
|
class != MULOP_CLASS && class != LOGOP_CLASS);
|
|||
|
pchCommand = pchComSaved;
|
|||
|
return fResult;
|
|||
|
}
|
|||
|
|
|||
|
/*** LookupSymbolInDll - Find the numeric value for a symbol from a
|
|||
|
* specific DLL
|
|||
|
*
|
|||
|
* Input:
|
|||
|
* symName - string with the symbol name to lookup
|
|||
|
* dllName - string with dll name in which to look
|
|||
|
*
|
|||
|
* Output:
|
|||
|
* none
|
|||
|
*
|
|||
|
* Returns:
|
|||
|
* returns value of symbol, or 0 if no symbol found in this dll.
|
|||
|
*
|
|||
|
*************************************************************************/
|
|||
|
|
|||
|
ULONG
|
|||
|
LookupSymbolInDll (
|
|||
|
PCHAR symName,
|
|||
|
PCHAR dllName
|
|||
|
)
|
|||
|
{
|
|||
|
ULONG retValue;
|
|||
|
PIMAGE_INFO pImage;
|
|||
|
char *imageStr;
|
|||
|
char *dllStr;
|
|||
|
|
|||
|
// skip over whitespace
|
|||
|
while (*symName == ' ' || *symName == '\t') {
|
|||
|
symName++;
|
|||
|
}
|
|||
|
|
|||
|
dllStr = _strdup(dllName);
|
|||
|
_strlwr(dllStr);
|
|||
|
|
|||
|
// First check all the exported symbols, if none found on
|
|||
|
// first pass, force symbol load on second.
|
|||
|
|
|||
|
for (pImage = pProcessCurrent->pImageHead;
|
|||
|
pImage;
|
|||
|
pImage = pImage->pImageNext) {
|
|||
|
imageStr = _strdup(pImage->szModuleName);
|
|||
|
_strlwr(imageStr);
|
|||
|
if (!strcmp(imageStr,dllStr)) {
|
|||
|
if (!GetOffsetFromSym( symName, &retValue, 0 )) {
|
|||
|
retValue = 0;
|
|||
|
}
|
|||
|
free(imageStr);
|
|||
|
free(dllStr);
|
|||
|
return(retValue);
|
|||
|
}
|
|||
|
free(imageStr);
|
|||
|
}
|
|||
|
free(dllStr);
|
|||
|
return(0);
|
|||
|
}
|