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);
|
||
}
|