//---------------------------------------------------------------------------- // // 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: * - starting address with default length * - inclusive address range * l - 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 ? "" : 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--; } }