+++ /dev/null
-/*
- * ReactOS kernel
- * Copyright (C) 2005 ReactOS Team
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-/*
- * PROJECT: ReactOS kernel
- * FILE: ntoskrnl/dbg/kdb_expr.c
- * PURPOSE: Kernel debugger expression evaluation
- * PROGRAMMER: Gregor Anich (blight@blight.eu.org)
- * UPDATE HISTORY:
- * Created 15/01/2005
- */
-
-/* Note:
- *
- * The given expression is parsed and stored in reverse polish notation,
- * then it is evaluated and the result is returned.
- */
-
-/* INCLUDES ******************************************************************/
-
-#include <ntoskrnl.h>
-#define NDEBUG
-#include <debug.h>
-
-/* TYPES *********************************************************************/
-typedef enum _RPN_OP_TYPE
-{
- RpnOpNop,
- RpnOpBinaryOperator,
- RpnOpUnaryOperator,
- RpnOpImmediate,
- RpnOpRegister,
- RpnOpDereference
-} RPN_OP_TYPE;
-
-typedef ULONGLONG (*RPN_BINARY_OPERATOR)(ULONGLONG a, ULONGLONG b);
-
-typedef struct _RPN_OP
-{
- RPN_OP_TYPE Type;
- ULONG CharacterOffset;
- union
- {
- /* RpnOpBinaryOperator */
- RPN_BINARY_OPERATOR BinaryOperator;
- /* RpnOpImmediate */
- ULONGLONG Immediate;
- /* RpnOpRegister */
- UCHAR Register;
- /* RpnOpDereference */
- UCHAR DerefMemorySize;
- }
- Data;
-}
-RPN_OP, *PRPN_OP;
-
-typedef struct _RPN_STACK
-{
- ULONG Size; /* Number of RPN_OPs on Ops */
- ULONG Sp; /* Stack pointer */
- RPN_OP Ops[1]; /* Array of RPN_OPs */
-}
-RPN_STACK, *PRPN_STACK;
-
-/* DEFINES *******************************************************************/
-#define stricmp _stricmp
-
-#ifndef RTL_FIELD_SIZE
-# define RTL_FIELD_SIZE(type, field) (sizeof(((type *)0)->field))
-#endif
-
-#define CONST_STRCPY(dst, src) \
- do { if ((dst)) { memcpy(dst, src, sizeof(src)); } } while (0);
-
-#define RPN_OP_STACK_SIZE 256
-#define RPN_VALUE_STACK_SIZE 256
-
-/* GLOBALS *******************************************************************/
-static struct
-{
- ULONG Size;
- ULONG Sp;
- RPN_OP Ops[RPN_OP_STACK_SIZE];
-}
-RpnStack =
-{
- RPN_OP_STACK_SIZE,
- 0
-};
-
-static const struct
-{
- PCHAR Name;
- UCHAR Offset;
- UCHAR Size;
-}
-RegisterToTrapFrame[] =
-{
- {"eip", FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Eip), RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Eip)},
- {"eflags", FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.EFlags), RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.EFlags)},
- {"eax", FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Eax), RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Eax)},
- {"ebx", FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Ebx), RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Ebx)},
- {"ecx", FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Ecx), RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Ecx)},
- {"edx", FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Edx), RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Edx)},
- {"esi", FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Esi), RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Esi)},
- {"edi", FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Edi), RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Edi)},
- {"esp", FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.HardwareEsp), RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.HardwareEsp)},
- {"ebp", FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Ebp), RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Ebp)},
- {"cs", FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.SegCs), 2 }, /* Use only the lower 2 bytes */
- {"ds", FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.SegDs), RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.SegDs)},
- {"es", FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.SegEs), RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.SegEs)},
- {"fs", FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.SegFs), RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.SegFs)},
- {"gs", FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.SegGs), RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.SegGs)},
- {"ss", FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.HardwareSegSs), RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.HardwareSegSs)},
- {"dr0", FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Dr0), RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Dr0)},
- {"dr1", FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Dr1), RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Dr1)},
- {"dr2", FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Dr2), RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Dr2)},
- {"dr3", FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Dr3), RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Dr3)},
- {"dr6", FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Dr6), RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Dr6)},
- {"dr7", FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Dr7), RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Dr7)},
- {"cr0", FIELD_OFFSET(KDB_KTRAP_FRAME, Cr0), RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Cr0)},
- {"cr2", FIELD_OFFSET(KDB_KTRAP_FRAME, Cr2), RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Cr2)},
- {"cr3", FIELD_OFFSET(KDB_KTRAP_FRAME, Cr3), RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Cr3)},
- {"cr4", FIELD_OFFSET(KDB_KTRAP_FRAME, Cr4), RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Cr4)}
-};
-static const INT RegisterToTrapFrameCount = sizeof (RegisterToTrapFrame) / sizeof (RegisterToTrapFrame[0]);
-
-/* FUNCTIONS *****************************************************************/
-
-ULONGLONG
-RpnBinaryOperatorAdd(
- ULONGLONG a,
- ULONGLONG b)
-{
- return a + b;
-}
-
-ULONGLONG
-RpnBinaryOperatorSub(
- ULONGLONG a,
- ULONGLONG b)
-{
- return a - b;
-}
-
-ULONGLONG
-RpnBinaryOperatorMul(
- ULONGLONG a,
- ULONGLONG b)
-{
- return a * b;
-}
-
-ULONGLONG
-RpnBinaryOperatorDiv(
- ULONGLONG a,
- ULONGLONG b)
-{
- return a / b;
-}
-
-ULONGLONG
-RpnBinaryOperatorMod(
- ULONGLONG a,
- ULONGLONG b)
-{
- return a % b;
-}
-
-ULONGLONG
-RpnBinaryOperatorEquals(
- ULONGLONG a,
- ULONGLONG b)
-{
- return (a == b);
-}
-
-ULONGLONG
-RpnBinaryOperatorNotEquals(
- ULONGLONG a,
- ULONGLONG b)
-{
- return (a != b);
-}
-
-ULONGLONG
-RpnBinaryOperatorLessThan(
- ULONGLONG a,
- ULONGLONG b)
-{
- return (a < b);
-}
-
-ULONGLONG
-RpnBinaryOperatorLessThanOrEquals(
- ULONGLONG a,
- ULONGLONG b)
-{
- return (a <= b);
-}
-
-ULONGLONG
-RpnBinaryOperatorGreaterThan(
- ULONGLONG a,
- ULONGLONG b)
-{
- return (a > b);
-}
-
-ULONGLONG
-RpnBinaryOperatorGreaterThanOrEquals(
- ULONGLONG a,
- ULONGLONG b)
-{
- return (a >= b);
-}
-
-/*!\brief Dumps the given RPN stack content
- *
- * \param Stack Pointer to a RPN_STACK structure.
- */
-VOID
-RpnpDumpStack(
- IN PRPN_STACK Stack)
-{
- ULONG ul;
-
- ASSERT(Stack);
- DbgPrint("\nStack size: %ld\n", Stack->Sp);
-
- for (ul = 0; ul < Stack->Sp; ul++)
- {
- PRPN_OP Op = Stack->Ops + ul;
- switch (Op->Type)
- {
- case RpnOpNop:
- DbgPrint("NOP,");
- break;
-
- case RpnOpImmediate:
- DbgPrint("0x%I64x,", Op->Data.Immediate);
- break;
-
- case RpnOpBinaryOperator:
- if (Op->Data.BinaryOperator == RpnBinaryOperatorAdd)
- DbgPrint("+,");
- else if (Op->Data.BinaryOperator == RpnBinaryOperatorSub)
- DbgPrint("-,");
- else if (Op->Data.BinaryOperator == RpnBinaryOperatorMul)
- DbgPrint("*,");
- else if (Op->Data.BinaryOperator == RpnBinaryOperatorDiv)
- DbgPrint("/,");
- else if (Op->Data.BinaryOperator == RpnBinaryOperatorMod)
- DbgPrint("%%,");
- else if (Op->Data.BinaryOperator == RpnBinaryOperatorEquals)
- DbgPrint("==,");
- else if (Op->Data.BinaryOperator == RpnBinaryOperatorNotEquals)
- DbgPrint("!=,");
- else if (Op->Data.BinaryOperator == RpnBinaryOperatorLessThan)
- DbgPrint("<,");
- else if (Op->Data.BinaryOperator == RpnBinaryOperatorLessThanOrEquals)
- DbgPrint("<=,");
- else if (Op->Data.BinaryOperator == RpnBinaryOperatorGreaterThan)
- DbgPrint(">,");
- else if (Op->Data.BinaryOperator == RpnBinaryOperatorGreaterThanOrEquals)
- DbgPrint(">=,");
- else
- DbgPrint("UNKNOWN OP,");
-
- break;
-
- case RpnOpRegister:
- DbgPrint("%s,", RegisterToTrapFrame[Op->Data.Register].Name);
- break;
-
- case RpnOpDereference:
- DbgPrint("[%s],",
- (Op->Data.DerefMemorySize == 1) ? ("byte") :
- ((Op->Data.DerefMemorySize == 2) ? ("word") :
- ((Op->Data.DerefMemorySize == 4) ? ("dword") : ("qword"))));
- break;
-
- default:
- DbgPrint("\nUnsupported Type: %d\n", Op->Type);
- ul = Stack->Sp;
- break;
- }
- }
-
- DbgPrint("\n");
-}
-
-/*!\brief Clears the given RPN stack.
- *
- * \param Stack Pointer to a RPN_STACK structure.
- */
-static VOID
-RpnpClearStack(
- OUT PRPN_STACK Stack)
-{
- ASSERT(Stack);
- Stack->Sp = 0;
-}
-
-/*!\brief Pushes an RPN_OP onto the stack.
- *
- * \param Stack Pointer to a RPN_STACK structure.
- * \param Op RPN_OP to be copied onto the stack.
- */
-static BOOLEAN
-RpnpPushStack(
- IN OUT PRPN_STACK Stack,
- IN PRPN_OP Op)
-{
- ASSERT(Stack);
- ASSERT(Op);
-
- if (Stack->Sp >= Stack->Size)
- return FALSE;
-
- memcpy(Stack->Ops + Stack->Sp, Op, sizeof (RPN_OP));
- Stack->Sp++;
-
- return TRUE;
-}
-
-/*!\brief Pops the top op from the stack.
- *
- * \param Stack Pointer to a RPN_STACK structure.
- * \param Op Pointer to an RPN_OP to store the popped op into (can be NULL).
- *
- * \retval TRUE Success.
- * \retval FALSE Failure (stack empty)
- */
-static BOOLEAN
-RpnpPopStack(
- IN OUT PRPN_STACK Stack,
- OUT PRPN_OP Op OPTIONAL)
-{
- ASSERT(Stack);
-
- if (Stack->Sp == 0)
- return FALSE;
-
- Stack->Sp--;
- if (Op)
- memcpy(Op, Stack->Ops + Stack->Sp, sizeof (RPN_OP));
-
- return TRUE;
-}
-
-/*!\brief Gets the top op from the stack (not popping it)
- *
- * \param Stack Pointer to a RPN_STACK structure.
- * \param Op Pointer to an RPN_OP to copy the top op into.
- *
- * \retval TRUE Success.
- * \retval FALSE Failure (stack empty)
- */
-static BOOLEAN
-RpnpTopStack(
- IN PRPN_STACK Stack,
- OUT PRPN_OP Op)
-{
- ASSERT(Stack);
- ASSERT(Op);
-
- if (Stack->Sp == 0)
- return FALSE;
-
- memcpy(Op, Stack->Ops + Stack->Sp - 1, sizeof (RPN_OP));
-
- return TRUE;
-}
-
-/*!\brief Parses an expression.
- *
- * This functions parses the given expression until the end of string or a closing
- * brace is found. As the function parses the string it pushes RPN_OPs onto the
- * stack.
- *
- * Examples: 1+2*3 ; eax+10 ; (eax+16) * (ebx+4) ; dword[eax]
- *
- * \param Stack Pointer to a RPN_STACK structure.
- * \param Expression String to parse.
- * \param CharacterOffset Character offset of the subexpression from the beginning of the expression.
- * \param End On success End is set to the character at which parsing stopped.
- * \param ErrOffset On failure this is set to the character offset at which the error occoured.
- * \param ErrMsg On failure a message describing the problem is copied into this buffer (128 bytes)
- *
- * \retval TRUE Success.
- * \retval FALSE Failure.
- */
-static BOOLEAN
-RpnpParseExpression(
- IN PRPN_STACK Stack,
- IN PCHAR Expression,
- OUT PCHAR *End OPTIONAL,
- IN ULONG CharacterOffset,
- OUT PLONG ErrOffset OPTIONAL,
- OUT PCHAR ErrMsg OPTIONAL)
-{
- PCHAR p = Expression;
- PCHAR pend;
- PCHAR Operator = NULL;
- LONG OperatorOffset = -1;
- RPN_OP RpnOp;
- RPN_OP PoppedOperator;
- BOOLEAN HavePoppedOperator = FALSE;
- RPN_OP ComparativeOp;
- BOOLEAN ComparativeOpFilled = FALSE;
- BOOLEAN IsComparativeOp;
- INT i, i2;
- ULONG ul;
- UCHAR MemorySize;
- CHAR Buffer[16];
- BOOLEAN First;
-
- ASSERT(Stack);
- ASSERT(Expression);
-
- First = TRUE;
- for (;;)
- {
- /* Skip whitespace */
- while (isspace(*p))
- {
- p++;
- CharacterOffset++;
- }
-
- /* Check for end of expression */
- if (p[0] == '\0' || p[0] == ')' || p[0] == ']')
- break;
-
- if (!First)
- {
- /* Remember operator */
- Operator = p++;
- OperatorOffset = CharacterOffset++;
-
- /* Pop operator (to get the right operator precedence) */
- HavePoppedOperator = FALSE;
- if (*Operator == '*' || *Operator == '/' || *Operator == '%')
- {
- if (RpnpTopStack(Stack, &PoppedOperator) &&
- PoppedOperator.Type == RpnOpBinaryOperator &&
- (PoppedOperator.Data.BinaryOperator == RpnBinaryOperatorAdd ||
- PoppedOperator.Data.BinaryOperator == RpnBinaryOperatorSub))
- {
- RpnpPopStack(Stack, NULL);
- HavePoppedOperator = TRUE;
- }
- else if (PoppedOperator.Type == RpnOpNop)
- {
- RpnpPopStack(Stack, NULL);
- /* Discard the NOP - it was only pushed to indicate there was a
- * closing brace, so the previous operator shouldn't be popped.
- */
- }
- }
- else if ((Operator[0] == '=' && Operator[1] == '=') ||
- (Operator[0] == '!' && Operator[1] == '=') ||
- Operator[0] == '<' || Operator[0] == '>')
- {
- if (Operator[0] == '=' || Operator[0] == '!' ||
- (Operator[0] == '<' && Operator[1] == '=') ||
- (Operator[0] == '>' && Operator[1] == '='))
- {
- p++;
- CharacterOffset++;
- }
-#if 0
- /* Parse rest of expression */
- if (!RpnpParseExpression(Stack, p + 1, &pend, CharacterOffset + 1,
- ErrOffset, ErrMsg))
- {
- return FALSE;
- }
- else if (pend == p + 1)
- {
- CONST_STRCPY(ErrMsg, "Expression expected");
-
- if (ErrOffset)
- *ErrOffset = CharacterOffset + 1;
-
- return FALSE;
- }
-
- goto end_of_expression; /* return */
-#endif
- }
- else if (Operator[0] != '+' && Operator[0] != '-')
- {
- CONST_STRCPY(ErrMsg, "Operator expected");
-
- if (ErrOffset)
- *ErrOffset = OperatorOffset;
-
- return FALSE;
- }
-
- /* Skip whitespace */
- while (isspace(*p))
- {
- p++;
- CharacterOffset++;
- }
- }
-
- /* Get operand */
- MemorySize = sizeof(ULONG_PTR); /* default to pointer size */
-
-get_operand:
- i = strcspn(p, "+-*/%()[]<>!=");
- if (i > 0)
- {
- i2 = i;
-
- /* Copy register name/memory size */
- while (isspace(p[--i2]));
-
- i2 = min(i2 + 1, (INT)sizeof (Buffer) - 1);
- strncpy(Buffer, p, i2);
- Buffer[i2] = '\0';
-
- /* Memory size prefix */
- if (p[i] == '[')
- {
- if (stricmp(Buffer, "byte") == 0)
- MemorySize = 1;
- else if (stricmp(Buffer, "word") == 0)
- MemorySize = 2;
- else if (stricmp(Buffer, "dword") == 0)
- MemorySize = 4;
- else if (stricmp(Buffer, "qword") == 0)
- MemorySize = 8;
- else
- {
- CONST_STRCPY(ErrMsg, "Invalid memory size prefix");
-
- if (ErrOffset)
- *ErrOffset = CharacterOffset;
-
- return FALSE;
- }
-
- p += i;
- CharacterOffset += i;
- goto get_operand;
- }
-
- /* Try to find register */
- for (i = 0; i < RegisterToTrapFrameCount; i++)
- {
- if (stricmp(RegisterToTrapFrame[i].Name, Buffer) == 0)
- break;
- }
-
- if (i < RegisterToTrapFrameCount)
- {
- RpnOp.Type = RpnOpRegister;
- RpnOp.CharacterOffset = CharacterOffset;
- RpnOp.Data.Register = i;
- i = strlen(RegisterToTrapFrame[i].Name);
- CharacterOffset += i;
- p += i;
- }
- else
- {
- /* Immediate value */
- /* FIXME: Need string to ULONGLONG function */
- ul = strtoul(p, &pend, 0);
- if (p != pend)
- {
- RpnOp.Type = RpnOpImmediate;
- RpnOp.CharacterOffset = CharacterOffset;
- RpnOp.Data.Immediate = (ULONGLONG)ul;
- CharacterOffset += pend - p;
- p = pend;
- }
- else
- {
- CONST_STRCPY(ErrMsg, "Operand expected");
-
- if (ErrOffset)
- *ErrOffset = CharacterOffset;
-
- return FALSE;
- }
- }
-
- /* Push operand */
- if (!RpnpPushStack(Stack, &RpnOp))
- {
- CONST_STRCPY(ErrMsg, "RPN op stack overflow");
-
- if (ErrOffset)
- *ErrOffset = -1;
-
- return FALSE;
- }
- }
- else if (i == 0)
- {
- if (p[0] == '(' || p[0] == '[') /* subexpression */
- {
- if (!RpnpParseExpression(Stack, p + 1, &pend, CharacterOffset + 1,
- ErrOffset, ErrMsg))
- {
- return FALSE;
- }
- else if (pend == p + 1)
- {
- CONST_STRCPY(ErrMsg, "Expression expected");
-
- if (ErrOffset)
- *ErrOffset = CharacterOffset + 1;
-
- return FALSE;
- }
-
- if (p[0] == '[') /* dereference */
- {
- ASSERT(MemorySize == 1 || MemorySize == 2 ||
- MemorySize == 4 || MemorySize == 8);
-
- if (pend[0] != ']')
- {
- CONST_STRCPY(ErrMsg, "']' expected");
-
- if (ErrOffset)
- *ErrOffset = CharacterOffset + (pend - p);
-
- return FALSE;
- }
-
- RpnOp.Type = RpnOpDereference;
- RpnOp.CharacterOffset = CharacterOffset;
- RpnOp.Data.DerefMemorySize = MemorySize;
-
- if (!RpnpPushStack(Stack, &RpnOp))
- {
- CONST_STRCPY(ErrMsg, "RPN op stack overflow");
-
- if (ErrOffset)
- *ErrOffset = -1;
-
- return FALSE;
- }
- }
- else /* p[0] == '(' */
- {
- if (pend[0] != ')')
- {
- CONST_STRCPY(ErrMsg, "')' expected");
-
- if (ErrOffset)
- *ErrOffset = CharacterOffset + (pend - p);
-
- return FALSE;
- }
- }
-
- /* Push a "nop" to prevent popping of the + operator (which would
- * result in (10+10)/2 beeing evaluated as 15)
- */
- RpnOp.Type = RpnOpNop;
- if (!RpnpPushStack(Stack, &RpnOp))
- {
- CONST_STRCPY(ErrMsg, "RPN op stack overflow");
-
- if (ErrOffset)
- *ErrOffset = -1;
-
- return FALSE;
- }
-
- /* Skip closing brace/bracket */
- pend++;
-
- CharacterOffset += pend - p;
- p = pend;
- }
- else if (First && p[0] == '-') /* Allow expressions like "- eax" */
- {
- RpnOp.Type = RpnOpImmediate;
- RpnOp.CharacterOffset = CharacterOffset;
- RpnOp.Data.Immediate = 0;
-
- if (!RpnpPushStack(Stack, &RpnOp))
- {
- CONST_STRCPY(ErrMsg, "RPN op stack overflow");
-
- if (ErrOffset)
- *ErrOffset = -1;
-
- return FALSE;
- }
- }
- else
- {
- CONST_STRCPY(ErrMsg, "Operand expected");
-
- if (ErrOffset)
- *ErrOffset = CharacterOffset;
-
- return FALSE;
- }
- }
- else
- {
- CONST_STRCPY(ErrMsg, "strcspn() failed");
-
- if (ErrOffset)
- *ErrOffset = -1;
-
- return FALSE;
- }
-
- if (!First)
- {
- /* Push operator */
- RpnOp.CharacterOffset = OperatorOffset;
- RpnOp.Type = RpnOpBinaryOperator;
- IsComparativeOp = FALSE;
-
- switch (*Operator)
- {
- case '+':
- RpnOp.Data.BinaryOperator = RpnBinaryOperatorAdd;
- break;
-
- case '-':
- RpnOp.Data.BinaryOperator = RpnBinaryOperatorSub;
- break;
-
- case '*':
- RpnOp.Data.BinaryOperator = RpnBinaryOperatorMul;
- break;
-
- case '/':
- RpnOp.Data.BinaryOperator = RpnBinaryOperatorDiv;
- break;
-
- case '%':
- RpnOp.Data.BinaryOperator = RpnBinaryOperatorMod;
- break;
-
- case '=':
- ASSERT(Operator[1] == '=');
- IsComparativeOp = TRUE;
- RpnOp.Data.BinaryOperator = RpnBinaryOperatorEquals;
- break;
-
- case '!':
- ASSERT(Operator[1] == '=');
- IsComparativeOp = TRUE;
- RpnOp.Data.BinaryOperator = RpnBinaryOperatorNotEquals;
- break;
-
- case '<':
- IsComparativeOp = TRUE;
-
- if (Operator[1] == '=')
- RpnOp.Data.BinaryOperator = RpnBinaryOperatorLessThanOrEquals;
- else
- RpnOp.Data.BinaryOperator = RpnBinaryOperatorLessThan;
-
- break;
-
- case '>':
- IsComparativeOp = TRUE;
-
- if (Operator[1] == '=')
- RpnOp.Data.BinaryOperator = RpnBinaryOperatorGreaterThanOrEquals;
- else
- RpnOp.Data.BinaryOperator = RpnBinaryOperatorGreaterThan;
-
- break;
-
- default:
- ASSERT(0);
- break;
- }
-
- if (IsComparativeOp)
- {
- if (ComparativeOpFilled && !RpnpPushStack(Stack, &ComparativeOp))
- {
- CONST_STRCPY(ErrMsg, "RPN op stack overflow");
-
- if (ErrOffset)
- *ErrOffset = -1;
-
- return FALSE;
- }
-
- memcpy(&ComparativeOp, &RpnOp, sizeof(RPN_OP));
- ComparativeOpFilled = TRUE;
- }
- else if (!RpnpPushStack(Stack, &RpnOp))
- {
- CONST_STRCPY(ErrMsg, "RPN op stack overflow");
-
- if (ErrOffset)
- *ErrOffset = -1;
-
- return FALSE;
- }
-
- /* Push popped operator */
- if (HavePoppedOperator)
- {
- if (!RpnpPushStack(Stack, &PoppedOperator))
- {
- CONST_STRCPY(ErrMsg, "RPN op stack overflow");
-
- if (ErrOffset)
- *ErrOffset = -1;
-
- return FALSE;
- }
- }
- }
-
- First = FALSE;
- }
-
-//end_of_expression:
-
- if (ComparativeOpFilled && !RpnpPushStack(Stack, &ComparativeOp))
- {
- CONST_STRCPY(ErrMsg, "RPN op stack overflow");
-
- if (ErrOffset)
- *ErrOffset = -1;
-
- return FALSE;
- }
-
- /* Skip whitespace */
- while (isspace(*p))
- {
- p++;
- CharacterOffset++;
- }
-
- if (End)
- *End = p;
-
- return TRUE;
-}
-
-/*!\brief Evaluates the RPN op stack and returns the result.
- *
- * \param Stack Pointer to a RPN_STACK structure.
- * \param TrapFrame Register values.
- * \param Result Pointer to an ULONG to store the result into.
- * \param ErrOffset On failure this is set to the character offset at which the error occoured.
- * \param ErrMsg Buffer which receives an error message on failure (128 bytes)
- *
- * \retval TRUE Success.
- * \retval FALSE Failure.
- */
-static BOOLEAN
-RpnpEvaluateStack(
- IN PRPN_STACK Stack,
- IN PKDB_KTRAP_FRAME TrapFrame,
- OUT PULONGLONG Result,
- OUT PLONG ErrOffset OPTIONAL,
- OUT PCHAR ErrMsg OPTIONAL)
-{
- ULONGLONG ValueStack[RPN_VALUE_STACK_SIZE];
- ULONG ValueStackPointer = 0;
- ULONG index;
- ULONGLONG ull;
- ULONG ul;
- USHORT us;
- UCHAR uc;
- PVOID p;
- BOOLEAN Ok;
-#ifdef DEBUG_RPN
- ULONG ValueStackPointerMax = 0;
-#endif
-
- ASSERT(Stack);
- ASSERT(TrapFrame);
- ASSERT(Result);
-
- for (index = 0; index < Stack->Sp; index++)
- {
- PRPN_OP Op = Stack->Ops + index;
-
-#ifdef DEBUG_RPN
- ValueStackPointerMax = max(ValueStackPointerMax, ValueStackPointer);
-#endif
-
- switch (Op->Type)
- {
- case RpnOpNop:
- /* No operation */
- break;
-
- case RpnOpImmediate:
- if (ValueStackPointer == RPN_VALUE_STACK_SIZE)
- {
- CONST_STRCPY(ErrMsg, "Value stack overflow");
-
- if (ErrOffset)
- *ErrOffset = -1;
-
- return FALSE;
- }
-
- ValueStack[ValueStackPointer++] = Op->Data.Immediate;
- break;
-
- case RpnOpRegister:
- if (ValueStackPointer == RPN_VALUE_STACK_SIZE)
- {
- CONST_STRCPY(ErrMsg, "Value stack overflow");
-
- if (ErrOffset)
- *ErrOffset = -1;
-
- return FALSE;
- }
-
- ul = Op->Data.Register;
- p = (PVOID)((ULONG_PTR)TrapFrame + RegisterToTrapFrame[ul].Offset);
-
- switch (RegisterToTrapFrame[ul].Size)
- {
- case 1: ull = (ULONGLONG)(*(PUCHAR)p); break;
- case 2: ull = (ULONGLONG)(*(PUSHORT)p); break;
- case 4: ull = (ULONGLONG)(*(PULONG)p); break;
- case 8: ull = (ULONGLONG)(*(PULONGLONG)p); break;
- default: ASSERT(0); return FALSE; break;
- }
-
- ValueStack[ValueStackPointer++] = ull;
- break;
-
- case RpnOpDereference:
- if (ValueStackPointer < 1)
- {
- CONST_STRCPY(ErrMsg, "Value stack underflow");
-
- if (ErrOffset)
- *ErrOffset = -1;
-
- return FALSE;
- }
-
- /* FIXME: Print a warning when address is out of range */
- p = (PVOID)(ULONG_PTR)ValueStack[ValueStackPointer - 1];
- Ok = FALSE;
-
- switch (Op->Data.DerefMemorySize)
- {
- case 1:
- if (NT_SUCCESS(KdbpSafeReadMemory(&uc, p, sizeof (uc))))
- {
- Ok = TRUE;
- ull = (ULONGLONG)uc;
- }
- break;
-
- case 2:
- if (NT_SUCCESS(KdbpSafeReadMemory(&us, p, sizeof (us))))
- {
- Ok = TRUE;
- ull = (ULONGLONG)us;
- }
- break;
-
- case 4:
- if (NT_SUCCESS(KdbpSafeReadMemory(&ul, p, sizeof (ul))))
- {
- Ok = TRUE;
- ull = (ULONGLONG)ul;
- }
- break;
-
- case 8:
- if (NT_SUCCESS(KdbpSafeReadMemory(&ull, p, sizeof (ull))))
- {
- Ok = TRUE;
- }
- break;
-
- default:
- ASSERT(0);
- return FALSE;
- break;
- }
-
- if (!Ok)
- {
- _snprintf(ErrMsg, 128, "Couldn't access memory at 0x%lx", (ULONG)p);
-
- if (ErrOffset)
- *ErrOffset = Op->CharacterOffset;
-
- return FALSE;
- }
-
- ValueStack[ValueStackPointer - 1] = ull;
- break;
-
- case RpnOpBinaryOperator:
- if (ValueStackPointer < 2)
- {
- CONST_STRCPY(ErrMsg, "Value stack underflow");
-
- if (ErrOffset)
- *ErrOffset = -1;
-
- return FALSE;
- }
-
- ValueStackPointer--;
- ull = ValueStack[ValueStackPointer];
-
- if (ull == 0 && Op->Data.BinaryOperator == RpnBinaryOperatorDiv)
- {
- CONST_STRCPY(ErrMsg, "Division by zero");
-
- if (ErrOffset)
- *ErrOffset = Op->CharacterOffset;
-
- return FALSE;
- }
-
- ull = Op->Data.BinaryOperator(ValueStack[ValueStackPointer - 1], ull);
- ValueStack[ValueStackPointer - 1] = ull;
- break;
-
- default:
- ASSERT(0);
- return FALSE;
- }
- }
-
-#ifdef DEBUG_RPN
- DPRINT1("Max value stack pointer: %d\n", ValueStackPointerMax);
-#endif
-
- if (ValueStackPointer != 1)
- {
- CONST_STRCPY(ErrMsg, "Stack not empty after evaluation");
-
- if (ErrOffset)
- *ErrOffset = -1;
-
- return FALSE;
- }
-
- *Result = ValueStack[0];
- return TRUE;
-}
-
-/*!\brief Evaluates the given expression
- *
- * \param Expression Expression to evaluate.
- * \param TrapFrame Register values.
- * \param Result Variable which receives the result on success.
- * \param ErrOffset Variable which receives character offset on parse error (-1 on other errors)
- * \param ErrMsg Buffer which receives an error message on failure (128 bytes)
- *
- * \retval TRUE Success.
- * \retval FALSE Failure.
- */
-BOOLEAN
-KdbpRpnEvaluateExpression(
- IN PCHAR Expression,
- IN PKDB_KTRAP_FRAME TrapFrame,
- OUT PULONGLONG Result,
- OUT PLONG ErrOffset OPTIONAL,
- OUT PCHAR ErrMsg OPTIONAL)
-{
- PRPN_STACK Stack = (PRPN_STACK)&RpnStack;
-
- ASSERT(Expression);
- ASSERT(TrapFrame);
- ASSERT(Result);
-
- /* Clear the stack and parse the expression */
- RpnpClearStack(Stack);
- if (!RpnpParseExpression(Stack, Expression, NULL, 0, ErrOffset, ErrMsg))
- return FALSE;
-
-#ifdef DEBUG_RPN
- RpnpDumpStack(Stack);
-#endif
-
- /* Evaluate the stack */
- if (!RpnpEvaluateStack(Stack, TrapFrame, Result, ErrOffset, ErrMsg))
- return FALSE;
-
- return TRUE;
-}
-
-/*!\brief Parses the given expression and returns a "handle" to it.
- *
- * \param Expression Expression to evaluate.
- * \param ErrOffset Variable which receives character offset on parse error (-1 on other errors)
- * \param ErrMsg Buffer which receives an error message on failure (128 bytes)
- *
- * \returns "Handle" for the expression, NULL on failure.
- *
- * \sa KdbpRpnEvaluateExpression
- */
-PVOID
-KdbpRpnParseExpression(
- IN PCHAR Expression,
- OUT PLONG ErrOffset OPTIONAL,
- OUT PCHAR ErrMsg OPTIONAL)
-{
- LONG Size;
- PRPN_STACK Stack = (PRPN_STACK)&RpnStack;
- PRPN_STACK NewStack;
-
- ASSERT(Expression);
-
- /* Clear the stack and parse the expression */
- RpnpClearStack(Stack);
- if (!RpnpParseExpression(Stack, Expression, NULL, 0, ErrOffset, ErrMsg))
- return FALSE;
-
-#ifdef DEBUG_RPN
- RpnpDumpStack(Stack);
-#endif
-
- /* Duplicate the stack and return a pointer/handle to it */
- ASSERT(Stack->Sp >= 1);
- Size = sizeof (RPN_STACK) + (RTL_FIELD_SIZE(RPN_STACK, Ops[0]) * (Stack->Sp - 1));
- NewStack = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_KDBG);
-
- if (!NewStack)
- {
- CONST_STRCPY(ErrMsg, "Out of memory");
-
- if (ErrOffset)
- *ErrOffset = -1;
-
- return NULL;
- }
-
- memcpy(NewStack, Stack, Size);
- NewStack->Size = NewStack->Sp;
-
- return NewStack;
-}
-
-/*!\brief Evaluates the given expression and returns the result.
- *
- * \param Expression Expression "handle" returned by KdbpRpnParseExpression.
- * \param TrapFrame Register values.
- * \param Result Variable which receives the result on success.
- * \param ErrOffset Variable which receives character offset on parse error (-1 on other errors)
- * \param ErrMsg Buffer which receives an error message on failure (128 bytes)
- *
- * \returns "Handle" for the expression, NULL on failure.
- *
- * \sa KdbpRpnParseExpression
- */
-BOOLEAN
-KdbpRpnEvaluateParsedExpression(
- IN PVOID Expression,
- IN PKDB_KTRAP_FRAME TrapFrame,
- OUT PULONGLONG Result,
- OUT PLONG ErrOffset OPTIONAL,
- OUT PCHAR ErrMsg OPTIONAL)
-{
- PRPN_STACK Stack = (PRPN_STACK)Expression;
-
- ASSERT(Expression);
- ASSERT(TrapFrame);
- ASSERT(Result);
-
- /* Evaluate the stack */
- return RpnpEvaluateStack(Stack, TrapFrame, Result, ErrOffset, ErrMsg);
-}
-