You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
608 lines
14 KiB
608 lines
14 KiB
//----------------------------------------------------------------------------
|
|
//
|
|
// General expression evaluation support.
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1990-2002.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "ntsdp.hpp"
|
|
|
|
ULONG g_EvalSyntax;
|
|
TypedData g_LastEvalResult;
|
|
|
|
EvalExpression* g_EvalReleaseChain;
|
|
EvalExpression* g_EvalCache[EVAL_COUNT];
|
|
|
|
EvalExpression*
|
|
GetEvaluator(ULONG Syntax, BOOL RetFail)
|
|
{
|
|
EvalExpression* Eval;
|
|
|
|
//
|
|
// Evaluators contain state and so a single
|
|
// global evaluator instance cannot be used
|
|
// if there's any possibility of nested
|
|
// evaluation. Instead we dynamically provide
|
|
// an evaluator any time there's a need for
|
|
// evaluation so that each nesting of a nested
|
|
// evaluation will have its own state.
|
|
//
|
|
|
|
Eval = g_EvalCache[Syntax];
|
|
if (Eval)
|
|
{
|
|
g_EvalCache[Syntax] = NULL;
|
|
}
|
|
else
|
|
{
|
|
switch(Syntax)
|
|
{
|
|
case DEBUG_EXPR_MASM:
|
|
Eval = new MasmEvalExpression;
|
|
break;
|
|
case DEBUG_EXPR_CPLUSPLUS:
|
|
Eval = new CppEvalExpression;
|
|
break;
|
|
default:
|
|
if (RetFail)
|
|
{
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
error(IMPLERR);
|
|
}
|
|
}
|
|
if (!Eval)
|
|
{
|
|
if (RetFail)
|
|
{
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
error(NOMEMORY);
|
|
}
|
|
}
|
|
}
|
|
|
|
Eval->m_ReleaseChain = g_EvalReleaseChain;
|
|
g_EvalReleaseChain = Eval;
|
|
|
|
return Eval;
|
|
}
|
|
|
|
void
|
|
ReleaseEvaluator(EvalExpression* Eval)
|
|
{
|
|
if (g_EvalReleaseChain == Eval)
|
|
{
|
|
g_EvalReleaseChain = Eval->m_ReleaseChain;
|
|
}
|
|
|
|
if (!g_EvalCache[Eval->m_Syntax])
|
|
{
|
|
Eval->Reset();
|
|
g_EvalCache[Eval->m_Syntax] = Eval;
|
|
}
|
|
else
|
|
{
|
|
delete Eval;
|
|
}
|
|
}
|
|
|
|
void
|
|
ReleaseEvaluators(void)
|
|
{
|
|
BOOL ChainTop = FALSE;
|
|
while (g_EvalReleaseChain && !ChainTop)
|
|
{
|
|
ChainTop = g_EvalReleaseChain->m_ChainTop;
|
|
ReleaseEvaluator(g_EvalReleaseChain);
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
GetEvaluatorByName(PCSTR AbbrevName, BOOL RetFail,
|
|
EvalExpression** EvalRet)
|
|
{
|
|
for (ULONG i = 0; i < EVAL_COUNT; i++)
|
|
{
|
|
EvalExpression* Eval = GetEvaluator(i, RetFail);
|
|
if (!Eval)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (!_stricmp(AbbrevName, Eval->m_AbbrevName))
|
|
{
|
|
*EvalRet = Eval;
|
|
return S_OK;
|
|
}
|
|
|
|
ReleaseEvaluator(Eval);
|
|
}
|
|
|
|
if (!RetFail)
|
|
{
|
|
error(SYNTAX);
|
|
}
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
CHAR
|
|
PeekChar(void)
|
|
{
|
|
CHAR Ch;
|
|
|
|
do
|
|
{
|
|
Ch = *g_CurCmd++;
|
|
} while (Ch == ' ' || Ch == '\t' || Ch == '\r' || Ch == '\n');
|
|
|
|
g_CurCmd--;
|
|
return Ch;
|
|
}
|
|
|
|
/*** 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:
|
|
* g_CurCmd - 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)
|
|
*
|
|
* Returns:
|
|
* A value of TRUE is returned if no length is specified, or a length
|
|
* or an ending address is specified and size is not zero. Otherwise,
|
|
* a value of FALSE is returned.
|
|
*
|
|
* Exceptions:
|
|
* error exit:
|
|
* SYNTAX - expression error
|
|
* BADRANGE - if ending address before starting address
|
|
*
|
|
*************************************************************************/
|
|
|
|
BOOL
|
|
GetRange(PADDR Addr,
|
|
PULONG64 Value,
|
|
ULONG Size,
|
|
ULONG SegReg,
|
|
ULONG SizeLimit)
|
|
{
|
|
CHAR Ch;
|
|
PSTR Scan;
|
|
ADDR EndRange;
|
|
BOOL HasL = FALSE;
|
|
BOOL HasLength;
|
|
BOOL WasSpace = FALSE;
|
|
|
|
// skip leading whitespace first
|
|
PeekChar();
|
|
|
|
// Pre-parse the line, look for a " L"
|
|
|
|
for (Scan = g_CurCmd; *Scan; Scan++)
|
|
{
|
|
if ((*Scan == 'L' || *Scan == 'l') && WasSpace)
|
|
{
|
|
HasL = TRUE;
|
|
*Scan = '\0';
|
|
break;
|
|
}
|
|
else if (*Scan == ';')
|
|
{
|
|
break;
|
|
}
|
|
|
|
WasSpace = *Scan == ' ';
|
|
}
|
|
|
|
HasLength = TRUE;
|
|
if ((Ch = PeekChar()) != '\0' && Ch != ';')
|
|
{
|
|
GetAddrExpression(SegReg, Addr);
|
|
if (((Ch = PeekChar()) != '\0' && Ch != ';') || HasL)
|
|
{
|
|
if (!HasL)
|
|
{
|
|
GetAddrExpression(SegReg, &EndRange);
|
|
if (AddrGt(*Addr, EndRange))
|
|
{
|
|
error(BADRANGE);
|
|
}
|
|
|
|
if (Size)
|
|
{
|
|
*Value = AddrDiff(EndRange, *Addr) / Size + 1;
|
|
}
|
|
else
|
|
{
|
|
*Value = Flat(EndRange);
|
|
HasLength = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
BOOL Invert;
|
|
|
|
g_CurCmd = Scan + 1;
|
|
if (*g_CurCmd == '-')
|
|
{
|
|
Invert = TRUE;
|
|
g_CurCmd++;
|
|
}
|
|
else
|
|
{
|
|
Invert = FALSE;
|
|
}
|
|
|
|
if (*g_CurCmd == '?')
|
|
{
|
|
// Turn off range length checking.
|
|
SizeLimit = 0;
|
|
g_CurCmd++;
|
|
}
|
|
|
|
*Value = GetExpressionDesc("Length of range missing from");
|
|
*Scan = 'l';
|
|
|
|
if (Invert)
|
|
{
|
|
// The user has given an l- range which indicates
|
|
// a length before the first address instead of
|
|
// a length after the first address.
|
|
if (Size)
|
|
{
|
|
AddrSub(Addr, *Value * Size);
|
|
}
|
|
else
|
|
{
|
|
ULONG64 Back = *Value;
|
|
*Value = Flat(*Addr);
|
|
AddrSub(Addr, Back);
|
|
HasLength = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// If the length is huge assume the user made
|
|
// some kind of mistake.
|
|
if (SizeLimit && Size && *Value * Size > SizeLimit)
|
|
{
|
|
error(BADRANGE);
|
|
}
|
|
}
|
|
}
|
|
|
|
return HasLength;
|
|
}
|
|
|
|
ULONG64
|
|
EvalStringNumAndCatch(PCSTR String)
|
|
{
|
|
ULONG64 Result;
|
|
|
|
EvalExpression* RelChain = g_EvalReleaseChain;
|
|
g_EvalReleaseChain = NULL;
|
|
|
|
__try
|
|
{
|
|
EvalExpression* Eval = GetCurEvaluator();
|
|
Result = Eval->EvalStringNum(String);
|
|
ReleaseEvaluator(Eval);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
Result = 0;
|
|
}
|
|
|
|
g_EvalReleaseChain = RelChain;
|
|
return Result;
|
|
}
|
|
|
|
ULONG64
|
|
GetExpression(void)
|
|
{
|
|
EvalExpression* Eval = GetCurEvaluator();
|
|
ULONG64 Result = Eval->EvalCurNum();
|
|
ReleaseEvaluator(Eval);
|
|
return Result;
|
|
}
|
|
|
|
ULONG64
|
|
GetExpressionDesc(PCSTR Desc)
|
|
{
|
|
EvalExpression* Eval = GetCurEvaluator();
|
|
ULONG64 Result = Eval->EvalCurNumDesc(Desc);
|
|
ReleaseEvaluator(Eval);
|
|
return Result;
|
|
}
|
|
|
|
ULONG64
|
|
GetTermExpression(PCSTR Desc)
|
|
{
|
|
EvalExpression* Eval = GetCurEvaluator();
|
|
ULONG64 Result = Eval->EvalCurTermNumDesc(Desc);
|
|
ReleaseEvaluator(Eval);
|
|
return Result;
|
|
}
|
|
|
|
void
|
|
GetAddrExpression(ULONG SegReg, PADDR Addr)
|
|
{
|
|
EvalExpression* Eval = GetCurEvaluator();
|
|
Eval->EvalCurAddr(SegReg, Addr);
|
|
ReleaseEvaluator(Eval);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// TypedDataStackAllocator.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void*
|
|
TypedDataStackAllocator::RawAlloc(ULONG Bytes)
|
|
{
|
|
void* Mem = malloc(Bytes);
|
|
if (!Mem)
|
|
{
|
|
m_Eval->EvalError(NOMEMORY);
|
|
}
|
|
return Mem;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// EvalExpression.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
// 'this' used in initializer list.
|
|
#pragma warning(disable:4355)
|
|
|
|
EvalExpression::EvalExpression(ULONG Syntax, PCSTR FullName, PCSTR AbbrevName)
|
|
: m_ResultAlloc(this)
|
|
{
|
|
m_Syntax = Syntax;
|
|
m_FullName = FullName;
|
|
m_AbbrevName = AbbrevName;
|
|
m_ParseOnly = 0;
|
|
m_AllowUnresolvedSymbols = 0;
|
|
m_NumUnresolvedSymbols = 0;
|
|
m_ReleaseChain = NULL;
|
|
m_ChainTop = TRUE;
|
|
m_Lex = NULL;
|
|
}
|
|
|
|
#pragma warning(default:4355)
|
|
|
|
EvalExpression::~EvalExpression(void)
|
|
{
|
|
}
|
|
|
|
void
|
|
EvalExpression::EvalCurrent(TypedData* Result)
|
|
{
|
|
g_CurCmd = (PSTR)
|
|
Evaluate(g_CurCmd, NULL, EXPRF_DEFAULT, Result);
|
|
}
|
|
|
|
void
|
|
EvalExpression::EvalCurAddrDesc(ULONG SegReg, PCSTR Desc, PADDR Addr)
|
|
{
|
|
//
|
|
// Evaluate a normal expression and then
|
|
// force the result to be an address.
|
|
//
|
|
|
|
if (Desc == NULL)
|
|
{
|
|
Desc = "Address expression missing from";
|
|
}
|
|
|
|
NotFlat(*Addr);
|
|
|
|
g_CurCmd = (PSTR)
|
|
EvaluateAddr(g_CurCmd, Desc, SegReg, Addr);
|
|
}
|
|
|
|
ULONG64
|
|
EvalExpression::EvalStringNum(PCSTR String)
|
|
{
|
|
ULONG Err;
|
|
TypedData Result;
|
|
|
|
Evaluate(String, "Numeric expression missing from",
|
|
EXPRF_DEFAULT, &Result);
|
|
if (Err = Result.ConvertToU64())
|
|
{
|
|
error(Err);
|
|
}
|
|
return Result.m_U64;
|
|
}
|
|
|
|
ULONG64
|
|
EvalExpression::EvalCurNumDesc(PCSTR Desc)
|
|
{
|
|
ULONG Err;
|
|
TypedData Result;
|
|
|
|
if (Desc == NULL)
|
|
{
|
|
Desc = "Numeric expression missing from";
|
|
}
|
|
|
|
g_CurCmd = (PSTR)
|
|
Evaluate(g_CurCmd, Desc, EXPRF_DEFAULT, &Result);
|
|
if (Err = Result.ConvertToU64())
|
|
{
|
|
error(Err);
|
|
}
|
|
return Result.m_U64;
|
|
}
|
|
|
|
ULONG64
|
|
EvalExpression::EvalCurTermNumDesc(PCSTR Desc)
|
|
{
|
|
ULONG Err;
|
|
TypedData Result;
|
|
|
|
if (Desc == NULL)
|
|
{
|
|
Desc = "Numeric term missing from";
|
|
}
|
|
|
|
g_CurCmd = (PSTR)
|
|
Evaluate(g_CurCmd, Desc, EXPRF_SINGLE_TERM, &Result);
|
|
if (Err = Result.ConvertToU64())
|
|
{
|
|
error(Err);
|
|
}
|
|
return Result.m_U64;
|
|
}
|
|
|
|
void DECLSPEC_NORETURN
|
|
EvalExpression::EvalErrorDesc(ULONG Error, PCSTR Desc)
|
|
{
|
|
if (!g_DisableErrorPrint)
|
|
{
|
|
PCSTR Text =
|
|
!m_LexemeSourceStart || !*m_LexemeSourceStart ?
|
|
"<EOL>" : m_LexemeSourceStart;
|
|
if (Desc != NULL)
|
|
{
|
|
ErrOut("%s '%s'\n", Desc, Text);
|
|
}
|
|
else
|
|
{
|
|
ErrOut("%s error at '%s'\n", ErrorString(Error), Text);
|
|
}
|
|
}
|
|
|
|
ReleaseEvaluators();
|
|
RaiseException(COMMAND_EXCEPTION_BASE + Error, 0, 0, NULL);
|
|
}
|
|
|
|
void
|
|
EvalExpression::Reset(void)
|
|
{
|
|
// Clear out any temporary memory that may have been allocated.
|
|
m_ResultAlloc.FreeAll();
|
|
m_NumUnresolvedSymbols = 0;
|
|
m_Lex = NULL;
|
|
m_ParseOnly = 0;
|
|
m_ReleaseChain = NULL;
|
|
}
|
|
|
|
void
|
|
EvalExpression::StartLexer(PCSTR Expr)
|
|
{
|
|
m_Lex = Expr;
|
|
m_LexemeRestart = m_LexemeBuffer;
|
|
m_LexemeSourceStart = NULL;
|
|
m_AllowUnaryOp = TRUE;
|
|
}
|
|
|
|
void
|
|
EvalExpression::Start(PCSTR Expr, PCSTR Desc, ULONG Flags)
|
|
{
|
|
// This class can't be used recursively.
|
|
if (m_Lex || m_ResultAlloc.NumAllocatedChunks())
|
|
{
|
|
error(IMPLERR);
|
|
}
|
|
|
|
RequireCurrentScope();
|
|
|
|
m_ExprDesc = Desc;
|
|
m_Flags = Flags;
|
|
|
|
m_Process = g_Process;
|
|
if (IS_CUR_MACHINE_ACCESSIBLE())
|
|
{
|
|
m_Machine = g_Machine;
|
|
}
|
|
else
|
|
{
|
|
m_Machine = NULL;
|
|
}
|
|
|
|
m_PtrSize = (m_Machine && m_Machine->m_Ptr64) ? 8 : 4;
|
|
|
|
StartLexer(Expr);
|
|
}
|
|
|
|
void
|
|
EvalExpression::End(TypedData* Result)
|
|
{
|
|
g_LastEvalResult = *Result;
|
|
// Allocator should have been left clean.
|
|
DBG_ASSERT(m_ResultAlloc.NumAllocatedChunks() == 0);
|
|
}
|
|
|
|
void
|
|
EvalExpression::AddLexeme(char Ch)
|
|
{
|
|
if (m_LexemeChar - m_LexemeBuffer >= sizeof(m_LexemeBuffer) - 1)
|
|
{
|
|
EvalErrorDesc(STRINGSIZE, "Lexeme too long in");
|
|
}
|
|
|
|
*m_LexemeChar++ = Ch;
|
|
}
|
|
|
|
void
|
|
EvalExpression::InheritStart(EvalExpression* Parent)
|
|
{
|
|
//
|
|
// Pick up heritable state from the parent.
|
|
//
|
|
|
|
if (Parent->m_ParseOnly)
|
|
{
|
|
m_ParseOnly++;
|
|
}
|
|
|
|
if (Parent->m_AllowUnresolvedSymbols)
|
|
{
|
|
m_AllowUnresolvedSymbols++;
|
|
}
|
|
}
|
|
|
|
void
|
|
EvalExpression::InheritEnd(EvalExpression* Parent)
|
|
{
|
|
//
|
|
// Pass heritable state back to the parent.
|
|
//
|
|
|
|
if (Parent->m_ParseOnly)
|
|
{
|
|
m_ParseOnly--;
|
|
}
|
|
|
|
if (Parent->m_AllowUnresolvedSymbols)
|
|
{
|
|
Parent->m_NumUnresolvedSymbols += m_NumUnresolvedSymbols;
|
|
m_AllowUnresolvedSymbols--;
|
|
}
|
|
}
|