3 * Copyright (C) 2005 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/dbg/kdb_expr.c
23 * PURPOSE: Kernel debugger expression evaluation
24 * PROGRAMMER: Gregor Anich (blight@blight.eu.org)
31 * The given expression is parsed and stored in reverse polish notation,
32 * then it is evaluated and the result is returned.
35 /* INCLUDES ******************************************************************/
39 #include <internal/debug.h>
41 /* TYPES *********************************************************************/
42 typedef enum _RPN_OP_TYPE
52 typedef ULONGLONG (*RPN_BINARY_OPERATOR
)(ULONGLONG a
, ULONGLONG b
);
54 typedef struct _RPN_OP
57 ULONG CharacterOffset
;
59 /* RpnOpBinaryOperator */
60 RPN_BINARY_OPERATOR BinaryOperator
;
65 /* RpnOpDereference */
66 UCHAR DerefMemorySize
;
70 typedef struct _RPN_STACK
72 ULONG Size
; /* Number of RPN_OPs on Ops */
73 ULONG Sp
; /* Stack pointer */
74 RPN_OP Ops
[1]; /* Array of RPN_OPs */
75 } RPN_STACK
, *PRPN_STACK
;
77 /* DEFINES *******************************************************************/
78 #define stricmp _stricmp
80 #ifndef RTL_FIELD_SIZE
81 # define RTL_FIELD_SIZE(type, field) (sizeof(((type *)0)->field))
84 #define CONST_STRCPY(dst, src) \
85 do { if ((dst) != NULL) { memcpy(dst, src, sizeof(src)); } } while (0);
87 #define RPN_OP_STACK_SIZE 256
88 #define RPN_VALUE_STACK_SIZE 256
90 /* GLOBALS *******************************************************************/
91 STATIC
struct { ULONG Size
; ULONG Sp
; RPN_OP Ops
[RPN_OP_STACK_SIZE
]; } RpnStack
= { RPN_OP_STACK_SIZE
, 0 };
93 STATIC CONST
struct { PCHAR Name
; UCHAR Offset
; UCHAR Size
; } RegisterToTrapFrame
[] =
95 {"eip", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Eip
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Eip
)},
96 {"eflags", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.EFlags
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.EFlags
)},
97 {"eax", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Eax
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Eax
)},
98 {"ebx", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Ebx
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Ebx
)},
99 {"ecx", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Ecx
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Ecx
)},
100 {"edx", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Edx
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Edx
)},
101 {"esi", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Esi
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Esi
)},
102 {"edi", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Edi
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Edi
)},
103 {"esp", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.HardwareEsp
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.HardwareEsp
)},
104 {"ebp", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Ebp
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Ebp
)},
105 {"cs", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.SegCs
), 2 }, /* Use only the lower 2 bytes */
106 {"ds", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.SegDs
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.SegDs
)},
107 {"es", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.SegEs
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.SegEs
)},
108 {"fs", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.SegFs
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.SegFs
)},
109 {"gs", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.SegGs
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.SegGs
)},
110 {"ss", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.HardwareSegSs
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.HardwareSegSs
)},
111 {"dr0", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Dr0
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Dr0
)},
112 {"dr1", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Dr1
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Dr1
)},
113 {"dr2", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Dr2
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Dr2
)},
114 {"dr3", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Dr3
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Dr3
)},
115 {"dr6", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Dr6
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Dr6
)},
116 {"dr7", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Dr7
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Dr7
)},
117 {"cr0", FIELD_OFFSET(KDB_KTRAP_FRAME
, Cr0
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Cr0
)},
118 {"cr2", FIELD_OFFSET(KDB_KTRAP_FRAME
, Cr2
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Cr2
)},
119 {"cr3", FIELD_OFFSET(KDB_KTRAP_FRAME
, Cr3
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Cr3
)},
120 {"cr4", FIELD_OFFSET(KDB_KTRAP_FRAME
, Cr4
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Cr4
)}
122 STATIC CONST INT RegisterToTrapFrameCount
=
123 sizeof (RegisterToTrapFrame
) / sizeof (RegisterToTrapFrame
[0]);
125 /* FUNCTIONS *****************************************************************/
128 RpnBinaryOperatorAdd(ULONGLONG a
, ULONGLONG b
)
134 RpnBinaryOperatorSub(ULONGLONG a
, ULONGLONG b
)
140 RpnBinaryOperatorMul(ULONGLONG a
, ULONGLONG b
)
146 RpnBinaryOperatorDiv(ULONGLONG a
, ULONGLONG b
)
153 RpnBinaryOperatorMod(ULONGLONG a
, ULONGLONG b
)
159 RpnBinaryOperatorEquals(ULONGLONG a
, ULONGLONG b
)
165 RpnBinaryOperatorNotEquals(ULONGLONG a
, ULONGLONG b
)
171 RpnBinaryOperatorLessThan(ULONGLONG a
, ULONGLONG b
)
177 RpnBinaryOperatorLessThanOrEquals(ULONGLONG a
, ULONGLONG b
)
183 RpnBinaryOperatorGreaterThan(ULONGLONG a
, ULONGLONG b
)
189 RpnBinaryOperatorGreaterThanOrEquals(ULONGLONG a
, ULONGLONG b
)
194 /*!\brief Dumps the given RPN stack content
196 * \param Stack Pointer to a RPN_STACK structure.
204 ASSERT(Stack
!= NULL
);
205 DbgPrint("\nStack size: %ld\n", Stack
->Sp
);
206 for (ul
= 0; ul
< Stack
->Sp
; ul
++)
208 PRPN_OP Op
= Stack
->Ops
+ ul
;
216 DbgPrint("0x%I64x,", Op
->Data
.Immediate
);
219 case RpnOpBinaryOperator
:
220 if (Op
->Data
.BinaryOperator
== RpnBinaryOperatorAdd
)
222 else if (Op
->Data
.BinaryOperator
== RpnBinaryOperatorSub
)
224 else if (Op
->Data
.BinaryOperator
== RpnBinaryOperatorMul
)
226 else if (Op
->Data
.BinaryOperator
== RpnBinaryOperatorDiv
)
228 else if (Op
->Data
.BinaryOperator
== RpnBinaryOperatorMod
)
230 else if (Op
->Data
.BinaryOperator
== RpnBinaryOperatorEquals
)
232 else if (Op
->Data
.BinaryOperator
== RpnBinaryOperatorNotEquals
)
234 else if (Op
->Data
.BinaryOperator
== RpnBinaryOperatorLessThan
)
236 else if (Op
->Data
.BinaryOperator
== RpnBinaryOperatorLessThanOrEquals
)
238 else if (Op
->Data
.BinaryOperator
== RpnBinaryOperatorGreaterThan
)
240 else if (Op
->Data
.BinaryOperator
== RpnBinaryOperatorGreaterThanOrEquals
)
243 DbgPrint("UNKNOWN OP,");
247 DbgPrint("%s,", RegisterToTrapFrame
[Op
->Data
.Register
].Name
);
250 case RpnOpDereference
:
252 (Op
->Data
.DerefMemorySize
== 1) ? ("byte") :
253 ((Op
->Data
.DerefMemorySize
== 2) ? ("word") :
254 ((Op
->Data
.DerefMemorySize
== 4) ? ("dword") : ("qword"))
260 DbgPrint("\nUnsupported Type: %d\n", Op
->Type
);
268 /*!\brief Clears the given RPN stack.
270 * \param Stack Pointer to a RPN_STACK structure.
274 OUT PRPN_STACK Stack
)
276 ASSERT(Stack
!= NULL
);
280 /*!\brief Pushes an RPN_OP onto the stack.
282 * \param Stack Pointer to a RPN_STACK structure.
283 * \param Op RPN_OP to be copied onto the stack.
287 IN OUT PRPN_STACK Stack
,
290 ASSERT(Stack
!= NULL
);
293 if (Stack
->Sp
>= Stack
->Size
)
296 memcpy(Stack
->Ops
+ Stack
->Sp
, Op
, sizeof (RPN_OP
));
301 /*!\brief Pops the top op from the stack.
303 * \param Stack Pointer to a RPN_STACK structure.
304 * \param Op Pointer to an RPN_OP to store the popped op into (can be NULL).
306 * \retval TRUE Success.
307 * \retval FALSE Failure (stack empty)
311 IN OUT PRPN_STACK Stack
,
312 OUT PRPN_OP Op OPTIONAL
)
314 ASSERT(Stack
!= NULL
);
321 memcpy(Op
, Stack
->Ops
+ Stack
->Sp
, sizeof (RPN_OP
));
325 /*!\brief Gets the top op from the stack (not popping it)
327 * \param Stack Pointer to a RPN_STACK structure.
328 * \param Op Pointer to an RPN_OP to copy the top op into.
330 * \retval TRUE Success.
331 * \retval FALSE Failure (stack empty)
338 ASSERT(Stack
!= NULL
);
344 memcpy(Op
, Stack
->Ops
+ Stack
->Sp
- 1, sizeof (RPN_OP
));
348 /*!\brief Parses an expression.
350 * This functions parses the given expression until the end of string or a closing
351 * brace is found. As the function parses the string it pushes RPN_OPs onto the
354 * Examples: 1+2*3 ; eax+10 ; (eax+16) * (ebx+4) ; dword[eax]
356 * \param Stack Pointer to a RPN_STACK structure.
357 * \param Expression String to parse.
358 * \param CharacterOffset Character offset of the subexpression from the beginning of the expression.
359 * \param End On success End is set to the character at which parsing stopped.
360 * \param ErrOffset On failure this is set to the character offset at which the error occoured.
361 * \param ErrMsg On failure a message describing the problem is copied into this buffer (128 bytes)
363 * \retval TRUE Success.
364 * \retval FALSE Failure.
370 OUT PCHAR
*End OPTIONAL
,
371 IN ULONG CharacterOffset
,
372 OUT PLONG ErrOffset OPTIONAL
,
373 OUT PCHAR ErrMsg OPTIONAL
)
375 PCHAR p
= Expression
;
377 PCHAR Operator
= NULL
;
378 LONG OperatorOffset
= -1;
380 RPN_OP PoppedOperator
;
381 BOOLEAN HavePoppedOperator
= FALSE
;
382 RPN_OP ComparativeOp
;
383 BOOLEAN ComparativeOpFilled
= FALSE
;
384 BOOLEAN IsComparativeOp
;
391 ASSERT(Stack
!= NULL
);
392 ASSERT(Expression
!= NULL
);
397 /* Skip whitespace */
404 /* Check for end of expression */
405 if (p
[0] == '\0' || p
[0] == ')' || p
[0] == ']')
410 /* Remember operator */
412 OperatorOffset
= CharacterOffset
++;
414 /* Pop operator (to get the right operator precedence) */
415 HavePoppedOperator
= FALSE
;
416 if (*Operator
== '*' || *Operator
== '/' || *Operator
== '%')
418 if (RpnpTopStack(Stack
, &PoppedOperator
) &&
419 PoppedOperator
.Type
== RpnOpBinaryOperator
&&
420 (PoppedOperator
.Data
.BinaryOperator
== RpnBinaryOperatorAdd
||
421 PoppedOperator
.Data
.BinaryOperator
== RpnBinaryOperatorSub
))
423 RpnpPopStack(Stack
, NULL
);
424 HavePoppedOperator
= TRUE
;
426 else if (PoppedOperator
.Type
== RpnOpNop
)
428 RpnpPopStack(Stack
, NULL
);
429 /* Discard the NOP - it was only pushed to indicate there was a
430 * closing brace, so the previous operator shouldn't be popped.
434 else if ((Operator
[0] == '=' && Operator
[1] == '=') ||
435 (Operator
[0] == '!' && Operator
[1] == '=') ||
436 Operator
[0] == '<' || Operator
[0] == '>')
438 if (Operator
[0] == '=' || Operator
[0] == '!' ||
439 (Operator
[0] == '<' && Operator
[1] == '=') ||
440 (Operator
[0] == '>' && Operator
[1] == '='))
446 /* Parse rest of expression */
447 if (!RpnpParseExpression(Stack
, p
+ 1, &pend
, CharacterOffset
+ 1,
452 else if (pend
== p
+ 1)
454 CONST_STRCPY(ErrMsg
, "Expression expected");
455 if (ErrOffset
!= NULL
)
456 *ErrOffset
= CharacterOffset
+ 1;
459 goto end_of_expression
; /* return */
462 else if (Operator
[0] != '+' && Operator
[0] != '-')
464 CONST_STRCPY(ErrMsg
, "Operator expected");
465 if (ErrOffset
!= NULL
)
466 *ErrOffset
= OperatorOffset
;
470 /* Skip whitespace */
479 MemorySize
= sizeof(ULONG_PTR
); /* default to pointer size */
481 i
= strcspn(p
, "+-*/%()[]<>!=");
486 /* Copy register name/memory size */
487 while (isspace(p
[--i2
]));
488 i2
= min(i2
+ 1, (INT
)sizeof (Buffer
) - 1);
489 strncpy(Buffer
, p
, i2
);
492 /* Memory size prefix */
495 if (stricmp(Buffer
, "byte") == 0)
497 else if (stricmp(Buffer
, "word") == 0)
499 else if (stricmp(Buffer
, "dword") == 0)
501 else if (stricmp(Buffer
, "qword") == 0)
505 CONST_STRCPY(ErrMsg
, "Invalid memory size prefix");
506 if (ErrOffset
!= NULL
)
507 *ErrOffset
= CharacterOffset
;
512 CharacterOffset
+= i
;
516 /* Try to find register */
517 for (i
= 0; i
< RegisterToTrapFrameCount
; i
++)
519 if (stricmp(RegisterToTrapFrame
[i
].Name
, Buffer
) == 0)
522 if (i
< RegisterToTrapFrameCount
)
524 RpnOp
.Type
= RpnOpRegister
;
525 RpnOp
.CharacterOffset
= CharacterOffset
;
526 RpnOp
.Data
.Register
= i
;
527 i
= strlen(RegisterToTrapFrame
[i
].Name
);
528 CharacterOffset
+= i
;
533 /* Immediate value */
534 /* FIXME: Need string to ULONGLONG function */
535 ul
= strtoul(p
, &pend
, 0);
538 RpnOp
.Type
= RpnOpImmediate
;
539 RpnOp
.CharacterOffset
= CharacterOffset
;
540 RpnOp
.Data
.Immediate
= (ULONGLONG
)ul
;
541 CharacterOffset
+= pend
- p
;
546 CONST_STRCPY(ErrMsg
, "Operand expected");
547 if (ErrOffset
!= NULL
)
548 *ErrOffset
= CharacterOffset
;
554 if (!RpnpPushStack(Stack
, &RpnOp
))
556 CONST_STRCPY(ErrMsg
, "RPN op stack overflow");
557 if (ErrOffset
!= NULL
)
564 if (p
[0] == '(' || p
[0] == '[') /* subexpression */
566 if (!RpnpParseExpression(Stack
, p
+ 1, &pend
, CharacterOffset
+ 1,
571 else if (pend
== p
+ 1)
573 CONST_STRCPY(ErrMsg
, "Expression expected");
574 if (ErrOffset
!= NULL
)
575 *ErrOffset
= CharacterOffset
+ 1;
579 if (p
[0] == '[') /* dereference */
581 ASSERT(MemorySize
== 1 || MemorySize
== 2 ||
582 MemorySize
== 4 || MemorySize
== 8);
585 CONST_STRCPY(ErrMsg
, "']' expected");
586 if (ErrOffset
!= NULL
)
587 *ErrOffset
= CharacterOffset
+ (pend
- p
);
590 RpnOp
.Type
= RpnOpDereference
;
591 RpnOp
.CharacterOffset
= CharacterOffset
;
592 RpnOp
.Data
.DerefMemorySize
= MemorySize
;
593 if (!RpnpPushStack(Stack
, &RpnOp
))
595 CONST_STRCPY(ErrMsg
, "RPN op stack overflow");
596 if (ErrOffset
!= NULL
)
601 else /* p[0] == '(' */
605 CONST_STRCPY(ErrMsg
, "')' expected");
606 if (ErrOffset
!= NULL
)
607 *ErrOffset
= CharacterOffset
+ (pend
- p
);
612 /* Push a "nop" to prevent popping of the + operator (which would
613 * result in (10+10)/2 beeing evaluated as 15)
615 RpnOp
.Type
= RpnOpNop
;
616 if (!RpnpPushStack(Stack
, &RpnOp
))
618 CONST_STRCPY(ErrMsg
, "RPN op stack overflow");
619 if (ErrOffset
!= NULL
)
624 /* Skip closing brace/bracket */
627 CharacterOffset
+= pend
- p
;
630 else if (First
&& p
[0] == '-') /* Allow expressions like "- eax" */
632 RpnOp
.Type
= RpnOpImmediate
;
633 RpnOp
.CharacterOffset
= CharacterOffset
;
634 RpnOp
.Data
.Immediate
= 0;
635 if (!RpnpPushStack(Stack
, &RpnOp
))
637 CONST_STRCPY(ErrMsg
, "RPN op stack overflow");
638 if (ErrOffset
!= NULL
)
645 CONST_STRCPY(ErrMsg
, "Operand expected");
646 if (ErrOffset
!= NULL
)
647 *ErrOffset
= CharacterOffset
;
653 CONST_STRCPY(ErrMsg
, "strcspn() failed");
654 if (ErrOffset
!= NULL
)
662 RpnOp
.CharacterOffset
= OperatorOffset
;
663 RpnOp
.Type
= RpnOpBinaryOperator
;
664 IsComparativeOp
= FALSE
;
668 RpnOp
.Data
.BinaryOperator
= RpnBinaryOperatorAdd
;
672 RpnOp
.Data
.BinaryOperator
= RpnBinaryOperatorSub
;
676 RpnOp
.Data
.BinaryOperator
= RpnBinaryOperatorMul
;
680 RpnOp
.Data
.BinaryOperator
= RpnBinaryOperatorDiv
;
684 RpnOp
.Data
.BinaryOperator
= RpnBinaryOperatorMod
;
688 ASSERT(Operator
[1] == '=');
689 IsComparativeOp
= TRUE
;
690 RpnOp
.Data
.BinaryOperator
= RpnBinaryOperatorEquals
;
694 ASSERT(Operator
[1] == '=');
695 IsComparativeOp
= TRUE
;
696 RpnOp
.Data
.BinaryOperator
= RpnBinaryOperatorNotEquals
;
700 IsComparativeOp
= TRUE
;
701 if (Operator
[1] == '=')
702 RpnOp
.Data
.BinaryOperator
= RpnBinaryOperatorLessThanOrEquals
;
704 RpnOp
.Data
.BinaryOperator
= RpnBinaryOperatorLessThan
;
708 IsComparativeOp
= TRUE
;
709 if (Operator
[1] == '=')
710 RpnOp
.Data
.BinaryOperator
= RpnBinaryOperatorGreaterThanOrEquals
;
712 RpnOp
.Data
.BinaryOperator
= RpnBinaryOperatorGreaterThan
;
721 if (ComparativeOpFilled
&& !RpnpPushStack(Stack
, &ComparativeOp
))
723 CONST_STRCPY(ErrMsg
, "RPN op stack overflow");
724 if (ErrOffset
!= NULL
)
728 memcpy(&ComparativeOp
, &RpnOp
, sizeof(RPN_OP
));
729 ComparativeOpFilled
= TRUE
;
731 else if (!RpnpPushStack(Stack
, &RpnOp
))
733 CONST_STRCPY(ErrMsg
, "RPN op stack overflow");
734 if (ErrOffset
!= NULL
)
739 /* Push popped operator */
740 if (HavePoppedOperator
)
742 if (!RpnpPushStack(Stack
, &PoppedOperator
))
744 CONST_STRCPY(ErrMsg
, "RPN op stack overflow");
745 if (ErrOffset
!= NULL
)
757 if (ComparativeOpFilled
&& !RpnpPushStack(Stack
, &ComparativeOp
))
759 CONST_STRCPY(ErrMsg
, "RPN op stack overflow");
760 if (ErrOffset
!= NULL
)
765 /* Skip whitespace */
778 /*!\brief Evaluates the RPN op stack and returns the result.
780 * \param Stack Pointer to a RPN_STACK structure.
781 * \param TrapFrame Register values.
782 * \param Result Pointer to an ULONG to store the result into.
783 * \param ErrOffset On failure this is set to the character offset at which the error occoured.
784 * \param ErrMsg Buffer which receives an error message on failure (128 bytes)
786 * \retval TRUE Success.
787 * \retval FALSE Failure.
792 IN PKDB_KTRAP_FRAME TrapFrame
,
793 OUT PULONGLONG Result
,
794 OUT PLONG ErrOffset OPTIONAL
,
795 OUT PCHAR ErrMsg OPTIONAL
)
797 ULONGLONG ValueStack
[RPN_VALUE_STACK_SIZE
];
798 ULONG ValueStackPointer
= 0;
807 ULONG ValueStackPointerMax
= 0;
810 ASSERT(Stack
!= NULL
);
811 ASSERT(TrapFrame
!= NULL
);
812 ASSERT(Result
!= NULL
);
814 for (index
= 0; index
< Stack
->Sp
; index
++)
816 PRPN_OP Op
= Stack
->Ops
+ index
;
819 ValueStackPointerMax
= max(ValueStackPointerMax
, ValueStackPointer
);
829 if (ValueStackPointer
== RPN_VALUE_STACK_SIZE
)
831 CONST_STRCPY(ErrMsg
, "Value stack overflow");
832 if (ErrOffset
!= NULL
)
836 ValueStack
[ValueStackPointer
++] = Op
->Data
.Immediate
;
840 if (ValueStackPointer
== RPN_VALUE_STACK_SIZE
)
842 CONST_STRCPY(ErrMsg
, "Value stack overflow");
843 if (ErrOffset
!= NULL
)
847 ul
= Op
->Data
.Register
;
848 p
= (PVOID
)((ULONG_PTR
)TrapFrame
+ RegisterToTrapFrame
[ul
].Offset
);
849 switch (RegisterToTrapFrame
[ul
].Size
)
851 case 1: ull
= (ULONGLONG
)(*(PUCHAR
)p
); break;
852 case 2: ull
= (ULONGLONG
)(*(PUSHORT
)p
); break;
853 case 4: ull
= (ULONGLONG
)(*(PULONG
)p
); break;
854 case 8: ull
= (ULONGLONG
)(*(PULONGLONG
)p
); break;
855 default: ASSERT(0); return FALSE
; break;
857 ValueStack
[ValueStackPointer
++] = ull
;
860 case RpnOpDereference
:
861 if (ValueStackPointer
< 1)
863 CONST_STRCPY(ErrMsg
, "Value stack underflow");
864 if (ErrOffset
!= NULL
)
869 /* FIXME: Print a warning when address is out of range */
870 p
= (PVOID
)(ULONG_PTR
)ValueStack
[ValueStackPointer
- 1];
872 switch (Op
->Data
.DerefMemorySize
)
875 if (NT_SUCCESS(KdbpSafeReadMemory(&uc
, p
, sizeof (uc
))))
882 if (NT_SUCCESS(KdbpSafeReadMemory(&us
, p
, sizeof (us
))))
889 if (NT_SUCCESS(KdbpSafeReadMemory(&ul
, p
, sizeof (ul
))))
896 if (NT_SUCCESS(KdbpSafeReadMemory(&ull
, p
, sizeof (ull
))))
908 _snprintf(ErrMsg
, 128, "Couldn't access memory at 0x%lx", (ULONG
)p
);
909 if (ErrOffset
!= NULL
)
910 *ErrOffset
= Op
->CharacterOffset
;
913 ValueStack
[ValueStackPointer
- 1] = ull
;
916 case RpnOpBinaryOperator
:
917 if (ValueStackPointer
< 2)
919 CONST_STRCPY(ErrMsg
, "Value stack underflow");
920 if (ErrOffset
!= NULL
)
925 ull
= ValueStack
[ValueStackPointer
];
926 if (ull
== 0 && (Op
->Data
.BinaryOperator
== RpnBinaryOperatorDiv
||
927 Op
->Data
.BinaryOperator
== RpnBinaryOperatorDiv
))
929 CONST_STRCPY(ErrMsg
, "Devision by zero");
930 if (ErrOffset
!= NULL
)
931 *ErrOffset
= Op
->CharacterOffset
;
934 ull
= Op
->Data
.BinaryOperator(ValueStack
[ValueStackPointer
- 1], ull
);
935 ValueStack
[ValueStackPointer
- 1] = ull
;
944 DPRINT1("Max value stack pointer: %d\n", ValueStackPointerMax
);
946 if (ValueStackPointer
!= 1)
948 CONST_STRCPY(ErrMsg
, "Stack not empty after evaluation");
949 if (ErrOffset
!= NULL
)
954 *Result
= ValueStack
[0];
958 /*!\brief Evaluates the given expression
960 * \param Expression Expression to evaluate.
961 * \param TrapFrame Register values.
962 * \param Result Variable which receives the result on success.
963 * \param ErrOffset Variable which receives character offset on parse error (-1 on other errors)
964 * \param ErrMsg Buffer which receives an error message on failure (128 bytes)
966 * \retval TRUE Success.
967 * \retval FALSE Failure.
970 KdbpRpnEvaluateExpression(
972 IN PKDB_KTRAP_FRAME TrapFrame
,
973 OUT PULONGLONG Result
,
974 OUT PLONG ErrOffset OPTIONAL
,
975 OUT PCHAR ErrMsg OPTIONAL
)
977 PRPN_STACK Stack
= (PRPN_STACK
)&RpnStack
;
979 ASSERT(Expression
!= NULL
);
980 ASSERT(TrapFrame
!= NULL
);
981 ASSERT(Result
!= NULL
);
983 /* Clear the stack and parse the expression */
984 RpnpClearStack(Stack
);
985 if (!RpnpParseExpression(Stack
, Expression
, NULL
, 0, ErrOffset
, ErrMsg
))
990 RpnpDumpStack(Stack
);
993 /* Evaluate the stack */
994 if (!RpnpEvaluateStack(Stack
, TrapFrame
, Result
, ErrOffset
, ErrMsg
))
1002 /*!\brief Parses the given expression and returns a "handle" to it.
1004 * \param Expression Expression to evaluate.
1005 * \param ErrOffset Variable which receives character offset on parse error (-1 on other errors)
1006 * \param ErrMsg Buffer which receives an error message on failure (128 bytes)
1008 * \returns "Handle" for the expression, NULL on failure.
1010 * \sa KdbpRpnEvaluateExpression
1013 KdbpRpnParseExpression(
1014 IN PCHAR Expression
,
1015 OUT PLONG ErrOffset OPTIONAL
,
1016 OUT PCHAR ErrMsg OPTIONAL
)
1019 PRPN_STACK Stack
= (PRPN_STACK
)&RpnStack
;
1020 PRPN_STACK NewStack
;
1022 ASSERT(Expression
!= NULL
);
1024 /* Clear the stack and parse the expression */
1025 RpnpClearStack(Stack
);
1026 if (!RpnpParseExpression(Stack
, Expression
, NULL
, 0, ErrOffset
, ErrMsg
))
1031 RpnpDumpStack(Stack
);
1034 /* Duplicate the stack and return a pointer/handle to it */
1035 ASSERT(Stack
->Sp
>= 1);
1036 Size
= sizeof (RPN_STACK
) + (RTL_FIELD_SIZE(RPN_STACK
, Ops
[0]) * (Stack
->Sp
- 1));
1037 NewStack
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_KDBG
);
1038 if (NewStack
== NULL
)
1040 CONST_STRCPY(ErrMsg
, "Out of memory");
1041 if (ErrOffset
!= NULL
)
1045 memcpy(NewStack
, Stack
, Size
);
1046 NewStack
->Size
= NewStack
->Sp
;
1051 /*!\brief Evaluates the given expression and returns the result.
1053 * \param Expression Expression "handle" returned by KdbpRpnParseExpression.
1054 * \param TrapFrame Register values.
1055 * \param Result Variable which receives the result on success.
1056 * \param ErrOffset Variable which receives character offset on parse error (-1 on other errors)
1057 * \param ErrMsg Buffer which receives an error message on failure (128 bytes)
1059 * \returns "Handle" for the expression, NULL on failure.
1061 * \sa KdbpRpnParseExpression
1064 KdbpRpnEvaluateParsedExpression(
1065 IN PVOID Expression
,
1066 IN PKDB_KTRAP_FRAME TrapFrame
,
1067 OUT PULONGLONG Result
,
1068 OUT PLONG ErrOffset OPTIONAL
,
1069 OUT PCHAR ErrMsg OPTIONAL
)
1071 PRPN_STACK Stack
= (PRPN_STACK
)Expression
;
1073 ASSERT(Expression
!= NULL
);
1074 ASSERT(TrapFrame
!= NULL
);
1075 ASSERT(Result
!= NULL
);
1077 /* Evaluate the stack */
1078 return RpnpEvaluateStack(Stack
, TrapFrame
, Result
, ErrOffset
, ErrMsg
);