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 ******************************************************************/
38 #include <internal/kdb.h>
40 #include <internal/debug.h>
42 /* TYPES *********************************************************************/
43 typedef enum _RPN_OP_TYPE
53 typedef ULONGLONG (*RPN_BINARY_OPERATOR
)(ULONGLONG a
, ULONGLONG b
);
55 typedef struct _RPN_OP
58 ULONG CharacterOffset
;
60 /* RpnOpBinaryOperator */
61 RPN_BINARY_OPERATOR BinaryOperator
;
66 /* RpnOpDereference */
67 UCHAR DerefMemorySize
;
71 typedef struct _RPN_STACK
73 ULONG Size
; /* Number of RPN_OPs on Ops */
74 ULONG Sp
; /* Stack pointer */
75 RPN_OP Ops
[1]; /* Array of RPN_OPs */
76 } RPN_STACK
, *PRPN_STACK
;
78 /* DEFINES *******************************************************************/
79 #define stricmp _stricmp
81 #ifndef RTL_FIELD_SIZE
82 # define RTL_FIELD_SIZE(type, field) (sizeof(((type *)0)->field))
85 #define CONST_STRCPY(dst, src) \
86 do { if ((dst) != NULL) { memcpy(dst, src, sizeof(src)); } } while (0);
88 #define RPN_OP_STACK_SIZE 256
89 #define RPN_VALUE_STACK_SIZE 256
91 /* GLOBALS *******************************************************************/
92 STATIC
struct { ULONG Size
; ULONG Sp
; RPN_OP Ops
[RPN_OP_STACK_SIZE
]; } RpnStack
= { RPN_OP_STACK_SIZE
, 0 };
94 STATIC CONST
struct { PCHAR Name
; UCHAR Offset
; UCHAR Size
; } RegisterToTrapFrame
[] =
96 {"eip", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Eip
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Eip
)},
97 {"eflags", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Eflags
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Eflags
)},
98 {"eax", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Eax
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Eax
)},
99 {"ebx", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Ebx
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Ebx
)},
100 {"ecx", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Ecx
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Ecx
)},
101 {"edx", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Edx
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Edx
)},
102 {"esi", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Esi
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Esi
)},
103 {"edi", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Edi
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Edi
)},
104 {"esp", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Esp
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Esp
)},
105 {"ebp", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Ebp
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Ebp
)},
106 {"cs", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Cs
), 2 }, /* Use only the lower 2 bytes */
107 {"ds", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Ds
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Ds
)},
108 {"es", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Es
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Es
)},
109 {"fs", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Fs
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Fs
)},
110 {"gs", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Gs
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Gs
)},
111 {"ss", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Ss
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Ss
)},
112 {"dr0", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Dr0
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Dr0
)},
113 {"dr1", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Dr1
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Dr1
)},
114 {"dr2", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Dr2
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Dr2
)},
115 {"dr3", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Dr3
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Dr3
)},
116 {"dr6", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Dr6
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Dr6
)},
117 {"dr7", FIELD_OFFSET(KDB_KTRAP_FRAME
, Tf
.Dr7
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Tf
.Dr7
)},
118 {"cr0", FIELD_OFFSET(KDB_KTRAP_FRAME
, Cr0
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Cr0
)},
119 {"cr2", FIELD_OFFSET(KDB_KTRAP_FRAME
, Cr2
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Cr2
)},
120 {"cr3", FIELD_OFFSET(KDB_KTRAP_FRAME
, Cr3
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Cr3
)},
121 {"cr4", FIELD_OFFSET(KDB_KTRAP_FRAME
, Cr4
), RTL_FIELD_SIZE(KDB_KTRAP_FRAME
, Cr4
)}
123 STATIC CONST INT RegisterToTrapFrameCount
=
124 sizeof (RegisterToTrapFrame
) / sizeof (RegisterToTrapFrame
[0]);
126 /* FUNCTIONS *****************************************************************/
129 RpnBinaryOperatorAdd(ULONGLONG a
, ULONGLONG b
)
135 RpnBinaryOperatorSub(ULONGLONG a
, ULONGLONG b
)
141 RpnBinaryOperatorMul(ULONGLONG a
, ULONGLONG b
)
147 RpnBinaryOperatorDiv(ULONGLONG a
, ULONGLONG b
)
154 RpnBinaryOperatorMod(ULONGLONG a
, ULONGLONG b
)
160 RpnBinaryOperatorEquals(ULONGLONG a
, ULONGLONG b
)
166 RpnBinaryOperatorNotEquals(ULONGLONG a
, ULONGLONG b
)
172 RpnBinaryOperatorLessThan(ULONGLONG a
, ULONGLONG b
)
178 RpnBinaryOperatorLessThanOrEquals(ULONGLONG a
, ULONGLONG b
)
184 RpnBinaryOperatorGreaterThan(ULONGLONG a
, ULONGLONG b
)
190 RpnBinaryOperatorGreaterThanOrEquals(ULONGLONG a
, ULONGLONG b
)
195 /*!\brief Dumps the given RPN stack content
197 * \param Stack Pointer to a RPN_STACK structure.
205 ASSERT(Stack
!= NULL
);
206 DbgPrint("\nStack size: %ld\n", Stack
->Sp
);
207 for (ul
= 0; ul
< Stack
->Sp
; ul
++)
209 PRPN_OP Op
= Stack
->Ops
+ ul
;
217 DbgPrint("0x%I64x,", Op
->Data
.Immediate
);
220 case RpnOpBinaryOperator
:
221 if (Op
->Data
.BinaryOperator
== RpnBinaryOperatorAdd
)
223 else if (Op
->Data
.BinaryOperator
== RpnBinaryOperatorSub
)
225 else if (Op
->Data
.BinaryOperator
== RpnBinaryOperatorMul
)
227 else if (Op
->Data
.BinaryOperator
== RpnBinaryOperatorDiv
)
229 else if (Op
->Data
.BinaryOperator
== RpnBinaryOperatorMod
)
231 else if (Op
->Data
.BinaryOperator
== RpnBinaryOperatorEquals
)
233 else if (Op
->Data
.BinaryOperator
== RpnBinaryOperatorNotEquals
)
235 else if (Op
->Data
.BinaryOperator
== RpnBinaryOperatorLessThan
)
237 else if (Op
->Data
.BinaryOperator
== RpnBinaryOperatorLessThanOrEquals
)
239 else if (Op
->Data
.BinaryOperator
== RpnBinaryOperatorGreaterThan
)
241 else if (Op
->Data
.BinaryOperator
== RpnBinaryOperatorGreaterThanOrEquals
)
244 DbgPrint("UNKNOWN OP,");
248 DbgPrint("%s,", RegisterToTrapFrame
[Op
->Data
.Register
].Name
);
251 case RpnOpDereference
:
253 (Op
->Data
.DerefMemorySize
== 1) ? ("byte") :
254 ((Op
->Data
.DerefMemorySize
== 2) ? ("word") :
255 ((Op
->Data
.DerefMemorySize
== 4) ? ("dword") : ("qword"))
261 DbgPrint("\nUnsupported Type: %d\n", Op
->Type
);
269 /*!\brief Clears the given RPN stack.
271 * \param Stack Pointer to a RPN_STACK structure.
275 OUT PRPN_STACK Stack
)
277 ASSERT(Stack
!= NULL
);
281 /*!\brief Pushes an RPN_OP onto the stack.
283 * \param Stack Pointer to a RPN_STACK structure.
284 * \param Op RPN_OP to be copied onto the stack.
288 IN OUT PRPN_STACK Stack
,
291 ASSERT(Stack
!= NULL
);
294 if (Stack
->Sp
>= Stack
->Size
)
297 memcpy(Stack
->Ops
+ Stack
->Sp
, Op
, sizeof (RPN_OP
));
302 /*!\brief Pops the top op from the stack.
304 * \param Stack Pointer to a RPN_STACK structure.
305 * \param Op Pointer to an RPN_OP to store the popped op into (can be NULL).
307 * \retval TRUE Success.
308 * \retval FALSE Failure (stack empty)
312 IN OUT PRPN_STACK Stack
,
313 OUT PRPN_OP Op OPTIONAL
)
315 ASSERT(Stack
!= NULL
);
322 memcpy(Op
, Stack
->Ops
+ Stack
->Sp
, sizeof (RPN_OP
));
326 /*!\brief Gets the top op from the stack (not popping it)
328 * \param Stack Pointer to a RPN_STACK structure.
329 * \param Op Pointer to an RPN_OP to copy the top op into.
331 * \retval TRUE Success.
332 * \retval FALSE Failure (stack empty)
339 ASSERT(Stack
!= NULL
);
345 memcpy(Op
, Stack
->Ops
+ Stack
->Sp
- 1, sizeof (RPN_OP
));
349 /*!\brief Parses an expression.
351 * This functions parses the given expression until the end of string or a closing
352 * brace is found. As the function parses the string it pushes RPN_OPs onto the
355 * Examples: 1+2*3 ; eax+10 ; (eax+16) * (ebx+4) ; dword[eax]
357 * \param Stack Pointer to a RPN_STACK structure.
358 * \param Expression String to parse.
359 * \param CharacterOffset Character offset of the subexpression from the beginning of the expression.
360 * \param End On success End is set to the character at which parsing stopped.
361 * \param ErrOffset On failure this is set to the character offset at which the error occoured.
362 * \param ErrMsg On failure a message describing the problem is copied into this buffer (128 bytes)
364 * \retval TRUE Success.
365 * \retval FALSE Failure.
371 OUT PCHAR
*End OPTIONAL
,
372 IN ULONG CharacterOffset
,
373 OUT PLONG ErrOffset OPTIONAL
,
374 OUT PCHAR ErrMsg OPTIONAL
)
376 PCHAR p
= Expression
;
378 PCHAR Operator
= NULL
;
379 LONG OperatorOffset
= -1;
381 RPN_OP PoppedOperator
;
382 BOOLEAN HavePoppedOperator
= FALSE
;
383 RPN_OP ComparativeOp
;
384 BOOLEAN ComparativeOpFilled
= FALSE
;
385 BOOLEAN IsComparativeOp
;
392 ASSERT(Stack
!= NULL
);
393 ASSERT(Expression
!= NULL
);
398 /* Skip whitespace */
405 /* Check for end of expression */
406 if (p
[0] == '\0' || p
[0] == ')' || p
[0] == ']')
411 /* Remember operator */
413 OperatorOffset
= CharacterOffset
++;;
415 /* Pop operator (to get the right operator precedence) */
416 HavePoppedOperator
= FALSE
;
417 if (*Operator
== '*' || *Operator
== '/' || *Operator
== '%')
419 if (RpnpTopStack(Stack
, &PoppedOperator
) &&
420 PoppedOperator
.Type
== RpnOpBinaryOperator
&&
421 (PoppedOperator
.Data
.BinaryOperator
== RpnBinaryOperatorAdd
||
422 PoppedOperator
.Data
.BinaryOperator
== RpnBinaryOperatorSub
))
424 RpnpPopStack(Stack
, NULL
);
425 HavePoppedOperator
= TRUE
;
427 else if (PoppedOperator
.Type
== RpnOpNop
)
429 RpnpPopStack(Stack
, NULL
);
430 /* Discard the NOP - it was only pushed to indicate there was a
431 * closing brace, so the previous operator shouldn't be popped.
435 else if ((Operator
[0] == '=' && Operator
[1] == '=') ||
436 (Operator
[0] == '!' && Operator
[1] == '=') ||
437 Operator
[0] == '<' || Operator
[0] == '>')
439 if (Operator
[0] == '=' || Operator
[0] == '!' ||
440 (Operator
[0] == '<' && Operator
[1] == '=') ||
441 (Operator
[0] == '>' && Operator
[1] == '='))
447 /* Parse rest of expression */
448 if (!RpnpParseExpression(Stack
, p
+ 1, &pend
, CharacterOffset
+ 1,
453 else if (pend
== p
+ 1)
455 CONST_STRCPY(ErrMsg
, "Expression expected");
456 if (ErrOffset
!= NULL
)
457 *ErrOffset
= CharacterOffset
+ 1;
460 goto end_of_expression
; /* return */
463 else if (Operator
[0] != '+' && Operator
[0] != '-')
465 CONST_STRCPY(ErrMsg
, "Operator expected");
466 if (ErrOffset
!= NULL
)
467 *ErrOffset
= OperatorOffset
;
471 /* Skip whitespace */
480 MemorySize
= sizeof(ULONG_PTR
); /* default to pointer size */
482 i
= strcspn(p
, "+-*/%()[]<>!=");
487 /* Copy register name/memory size */
488 while (isspace(p
[--i2
]));
489 i2
= min(i2
+ 1, sizeof (Buffer
) - 1);
490 strncpy(Buffer
, p
, i2
);
493 /* Memory size prefix */
496 if (stricmp(Buffer
, "byte") == 0)
498 else if (stricmp(Buffer
, "word") == 0)
500 else if (stricmp(Buffer
, "dword") == 0)
502 else if (stricmp(Buffer
, "qword") == 0)
506 CONST_STRCPY(ErrMsg
, "Invalid memory size prefix");
507 if (ErrOffset
!= NULL
)
508 *ErrOffset
= CharacterOffset
;
513 CharacterOffset
+= i
;
517 /* Try to find register */
518 for (i
= 0; i
< RegisterToTrapFrameCount
; i
++)
520 if (stricmp(RegisterToTrapFrame
[i
].Name
, Buffer
) == 0)
523 if (i
< RegisterToTrapFrameCount
)
525 RpnOp
.Type
= RpnOpRegister
;
526 RpnOp
.CharacterOffset
= CharacterOffset
;
527 RpnOp
.Data
.Register
= i
;
528 i
= strlen(RegisterToTrapFrame
[i
].Name
);
529 CharacterOffset
+= i
;
534 /* Immediate value */
535 /* FIXME: Need string to ULONGLONG function */
536 ul
= strtoul(p
, &pend
, 0);
539 RpnOp
.Type
= RpnOpImmediate
;
540 RpnOp
.CharacterOffset
= CharacterOffset
;
541 RpnOp
.Data
.Immediate
= (ULONGLONG
)ul
;
542 CharacterOffset
+= pend
- p
;
547 CONST_STRCPY(ErrMsg
, "Operand expected");
548 if (ErrOffset
!= NULL
)
549 *ErrOffset
= CharacterOffset
;
555 if (!RpnpPushStack(Stack
, &RpnOp
))
557 CONST_STRCPY(ErrMsg
, "RPN op stack overflow");
558 if (ErrOffset
!= NULL
)
565 if (p
[0] == '(' || p
[0] == '[') /* subexpression */
567 if (!RpnpParseExpression(Stack
, p
+ 1, &pend
, CharacterOffset
+ 1,
572 else if (pend
== p
+ 1)
574 CONST_STRCPY(ErrMsg
, "Expression expected");
575 if (ErrOffset
!= NULL
)
576 *ErrOffset
= CharacterOffset
+ 1;
580 if (p
[0] == '[') /* dereference */
582 ASSERT(MemorySize
== 1 || MemorySize
== 2 ||
583 MemorySize
== 4 || MemorySize
== 8);
586 CONST_STRCPY(ErrMsg
, "']' expected");
587 if (ErrOffset
!= NULL
)
588 *ErrOffset
= CharacterOffset
+ (pend
- p
);
591 RpnOp
.Type
= RpnOpDereference
;
592 RpnOp
.CharacterOffset
= CharacterOffset
;
593 RpnOp
.Data
.DerefMemorySize
= MemorySize
;
594 if (!RpnpPushStack(Stack
, &RpnOp
))
596 CONST_STRCPY(ErrMsg
, "RPN op stack overflow");
597 if (ErrOffset
!= NULL
)
602 else /* p[0] == '(' */
606 CONST_STRCPY(ErrMsg
, "')' expected");
607 if (ErrOffset
!= NULL
)
608 *ErrOffset
= CharacterOffset
+ (pend
- p
);
613 /* Push a "nop" to prevent popping of the + operator (which would
614 * result in (10+10)/2 beeing evaluated as 15)
616 RpnOp
.Type
= RpnOpNop
;
617 if (!RpnpPushStack(Stack
, &RpnOp
))
619 CONST_STRCPY(ErrMsg
, "RPN op stack overflow");
620 if (ErrOffset
!= NULL
)
625 /* Skip closing brace/bracket */
628 CharacterOffset
+= pend
- p
;
631 else if (First
&& p
[0] == '-') /* Allow expressions like "- eax" */
633 RpnOp
.Type
= RpnOpImmediate
;
634 RpnOp
.CharacterOffset
= CharacterOffset
;
635 RpnOp
.Data
.Immediate
= 0;
636 if (!RpnpPushStack(Stack
, &RpnOp
))
638 CONST_STRCPY(ErrMsg
, "RPN op stack overflow");
639 if (ErrOffset
!= NULL
)
646 CONST_STRCPY(ErrMsg
, "Operand expected");
647 if (ErrOffset
!= NULL
)
648 *ErrOffset
= CharacterOffset
;
654 CONST_STRCPY(ErrMsg
, "strcspn() failed");
655 if (ErrOffset
!= NULL
)
663 RpnOp
.CharacterOffset
= OperatorOffset
;
664 RpnOp
.Type
= RpnOpBinaryOperator
;
665 IsComparativeOp
= FALSE
;
669 RpnOp
.Data
.BinaryOperator
= RpnBinaryOperatorAdd
;
673 RpnOp
.Data
.BinaryOperator
= RpnBinaryOperatorSub
;
677 RpnOp
.Data
.BinaryOperator
= RpnBinaryOperatorMul
;
681 RpnOp
.Data
.BinaryOperator
= RpnBinaryOperatorDiv
;
685 RpnOp
.Data
.BinaryOperator
= RpnBinaryOperatorMod
;
689 ASSERT(Operator
[1] == '=');
690 IsComparativeOp
= TRUE
;
691 RpnOp
.Data
.BinaryOperator
= RpnBinaryOperatorEquals
;
695 ASSERT(Operator
[1] == '=');
696 IsComparativeOp
= TRUE
;
697 RpnOp
.Data
.BinaryOperator
= RpnBinaryOperatorNotEquals
;
701 IsComparativeOp
= TRUE
;
702 if (Operator
[1] == '=')
703 RpnOp
.Data
.BinaryOperator
= RpnBinaryOperatorLessThanOrEquals
;
705 RpnOp
.Data
.BinaryOperator
= RpnBinaryOperatorLessThan
;
709 IsComparativeOp
= TRUE
;
710 if (Operator
[1] == '=')
711 RpnOp
.Data
.BinaryOperator
= RpnBinaryOperatorGreaterThanOrEquals
;
713 RpnOp
.Data
.BinaryOperator
= RpnBinaryOperatorGreaterThan
;
722 if (ComparativeOpFilled
&& !RpnpPushStack(Stack
, &ComparativeOp
))
724 CONST_STRCPY(ErrMsg
, "RPN op stack overflow");
725 if (ErrOffset
!= NULL
)
729 memcpy(&ComparativeOp
, &RpnOp
, sizeof(RPN_OP
));
730 ComparativeOpFilled
= TRUE
;
732 else if (!RpnpPushStack(Stack
, &RpnOp
))
734 CONST_STRCPY(ErrMsg
, "RPN op stack overflow");
735 if (ErrOffset
!= NULL
)
740 /* Push popped operator */
741 if (HavePoppedOperator
)
743 if (!RpnpPushStack(Stack
, &PoppedOperator
))
745 CONST_STRCPY(ErrMsg
, "RPN op stack overflow");
746 if (ErrOffset
!= NULL
)
758 if (ComparativeOpFilled
&& !RpnpPushStack(Stack
, &ComparativeOp
))
760 CONST_STRCPY(ErrMsg
, "RPN op stack overflow");
761 if (ErrOffset
!= NULL
)
766 /* Skip whitespace */
779 /*!\brief Evaluates the RPN op stack and returns the result.
781 * \param Stack Pointer to a RPN_STACK structure.
782 * \param TrapFrame Register values.
783 * \param Result Pointer to an ULONG to store the result into.
784 * \param ErrOffset On failure this is set to the character offset at which the error occoured.
785 * \param ErrMsg Buffer which receives an error message on failure (128 bytes)
787 * \retval TRUE Success.
788 * \retval FALSE Failure.
793 IN PKDB_KTRAP_FRAME TrapFrame
,
794 OUT PULONGLONG Result
,
795 OUT PLONG ErrOffset OPTIONAL
,
796 OUT PCHAR ErrMsg OPTIONAL
)
798 ULONGLONG ValueStack
[RPN_VALUE_STACK_SIZE
];
799 ULONG ValueStackPointer
= 0;
808 ULONG ValueStackPointerMax
= 0;
811 ASSERT(Stack
!= NULL
);
812 ASSERT(TrapFrame
!= NULL
);
813 ASSERT(Result
!= NULL
);
815 for (index
= 0; index
< Stack
->Sp
; index
++)
817 PRPN_OP Op
= Stack
->Ops
+ index
;
820 ValueStackPointerMax
= max(ValueStackPointerMax
, ValueStackPointer
);
830 if (ValueStackPointer
== RPN_VALUE_STACK_SIZE
)
832 CONST_STRCPY(ErrMsg
, "Value stack overflow");
833 if (ErrOffset
!= NULL
)
837 ValueStack
[ValueStackPointer
++] = Op
->Data
.Immediate
;
841 if (ValueStackPointer
== RPN_VALUE_STACK_SIZE
)
843 CONST_STRCPY(ErrMsg
, "Value stack overflow");
844 if (ErrOffset
!= NULL
)
848 ul
= Op
->Data
.Register
;
849 p
= (PVOID
)((ULONG_PTR
)TrapFrame
+ RegisterToTrapFrame
[ul
].Offset
);
850 switch (RegisterToTrapFrame
[ul
].Size
)
852 case 1: ull
= (ULONGLONG
)(*(PUCHAR
)p
); break;
853 case 2: ull
= (ULONGLONG
)(*(PUSHORT
)p
); break;
854 case 4: ull
= (ULONGLONG
)(*(PULONG
)p
); break;
855 case 8: ull
= (ULONGLONG
)(*(PULONGLONG
)p
); break;
856 default: ASSERT(0); return FALSE
; break;
858 ValueStack
[ValueStackPointer
++] = ull
;
861 case RpnOpDereference
:
862 if (ValueStackPointer
< 1)
864 CONST_STRCPY(ErrMsg
, "Value stack underflow");
865 if (ErrOffset
!= NULL
)
870 /* FIXME: Print a warning when address is out of range */
871 p
= (PVOID
)(ULONG_PTR
)ValueStack
[ValueStackPointer
- 1];
873 switch (Op
->Data
.DerefMemorySize
)
876 if (NT_SUCCESS(KdbpSafeReadMemory(&uc
, p
, sizeof (uc
))))
883 if (NT_SUCCESS(KdbpSafeReadMemory(&us
, p
, sizeof (us
))))
890 if (NT_SUCCESS(KdbpSafeReadMemory(&ul
, p
, sizeof (ul
))))
897 if (NT_SUCCESS(KdbpSafeReadMemory(&ull
, p
, sizeof (ull
))))
909 _snprintf(ErrMsg
, 128, "Couldn't access memory at 0x%lx", (ULONG
)p
);
910 if (ErrOffset
!= NULL
)
911 *ErrOffset
= Op
->CharacterOffset
;
914 ValueStack
[ValueStackPointer
- 1] = ull
;
917 case RpnOpBinaryOperator
:
918 if (ValueStackPointer
< 2)
920 CONST_STRCPY(ErrMsg
, "Value stack underflow");
921 if (ErrOffset
!= NULL
)
926 ull
= ValueStack
[ValueStackPointer
];
927 if (ull
== 0 && (Op
->Data
.BinaryOperator
== RpnBinaryOperatorDiv
||
928 Op
->Data
.BinaryOperator
== RpnBinaryOperatorDiv
))
930 CONST_STRCPY(ErrMsg
, "Devision by zero");
931 if (ErrOffset
!= NULL
)
932 *ErrOffset
= Op
->CharacterOffset
;
935 ull
= Op
->Data
.BinaryOperator(ValueStack
[ValueStackPointer
- 1], ull
);
936 ValueStack
[ValueStackPointer
- 1] = ull
;
945 DPRINT1("Max value stack pointer: %d\n", ValueStackPointerMax
);
947 if (ValueStackPointer
!= 1)
949 CONST_STRCPY(ErrMsg
, "Stack not empty after evaluation");
950 if (ErrOffset
!= NULL
)
955 *Result
= ValueStack
[0];
959 /*!\brief Evaluates the given expression
961 * \param Expression Expression to evaluate.
962 * \param TrapFrame Register values.
963 * \param Result Variable which receives the result on success.
964 * \param ErrOffset Variable which receives character offset on parse error (-1 on other errors)
965 * \param ErrMsg Buffer which receives an error message on failure (128 bytes)
967 * \retval TRUE Success.
968 * \retval FALSE Failure.
971 KdbpRpnEvaluateExpression(
973 IN PKDB_KTRAP_FRAME TrapFrame
,
974 OUT PULONGLONG Result
,
975 OUT PLONG ErrOffset OPTIONAL
,
976 OUT PCHAR ErrMsg OPTIONAL
)
978 PRPN_STACK Stack
= (PRPN_STACK
)&RpnStack
;
980 ASSERT(Expression
!= NULL
);
981 ASSERT(TrapFrame
!= NULL
);
982 ASSERT(Result
!= NULL
);
984 /* Clear the stack and parse the expression */
985 RpnpClearStack(Stack
);
986 if (!RpnpParseExpression(Stack
, Expression
, NULL
, 0, ErrOffset
, ErrMsg
))
991 RpnpDumpStack(Stack
);
994 /* Evaluate the stack */
995 if (!RpnpEvaluateStack(Stack
, TrapFrame
, Result
, ErrOffset
, ErrMsg
))
1003 /*!\brief Parses the given expression and returns a "handle" to it.
1005 * \param Expression Expression to evaluate.
1006 * \param ErrOffset Variable which receives character offset on parse error (-1 on other errors)
1007 * \param ErrMsg Buffer which receives an error message on failure (128 bytes)
1009 * \returns "Handle" for the expression, NULL on failure.
1011 * \sa KdbpRpnEvaluateExpression
1014 KdbpRpnParseExpression(
1015 IN PCHAR Expression
,
1016 OUT PLONG ErrOffset OPTIONAL
,
1017 OUT PCHAR ErrMsg OPTIONAL
)
1020 PRPN_STACK Stack
= (PRPN_STACK
)&RpnStack
;
1021 PRPN_STACK NewStack
;
1023 ASSERT(Expression
!= NULL
);
1025 /* Clear the stack and parse the expression */
1026 RpnpClearStack(Stack
);
1027 if (!RpnpParseExpression(Stack
, Expression
, NULL
, 0, ErrOffset
, ErrMsg
))
1032 RpnpDumpStack(Stack
);
1035 /* Duplicate the stack and return a pointer/handle to it */
1036 ASSERT(Stack
->Sp
>= 1);
1037 Size
= sizeof (RPN_STACK
) + (RTL_FIELD_SIZE(RPN_STACK
, Ops
[0]) * (Stack
->Sp
- 1));
1038 NewStack
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_KDBG
);
1039 if (NewStack
== NULL
)
1041 CONST_STRCPY(ErrMsg
, "Out of memory");
1042 if (ErrOffset
!= NULL
)
1046 memcpy(NewStack
, Stack
, Size
);
1047 NewStack
->Size
= NewStack
->Sp
;
1052 /*!\brief Evaluates the given expression and returns the result.
1054 * \param Expression Expression "handle" returned by KdbpRpnParseExpression.
1055 * \param TrapFrame Register values.
1056 * \param Result Variable which receives the result on success.
1057 * \param ErrOffset Variable which receives character offset on parse error (-1 on other errors)
1058 * \param ErrMsg Buffer which receives an error message on failure (128 bytes)
1060 * \returns "Handle" for the expression, NULL on failure.
1062 * \sa KdbpRpnParseExpression
1065 KdbpRpnEvaluateParsedExpression(
1066 IN PVOID Expression
,
1067 IN PKDB_KTRAP_FRAME TrapFrame
,
1068 OUT PULONGLONG Result
,
1069 OUT PLONG ErrOffset OPTIONAL
,
1070 OUT PCHAR ErrMsg OPTIONAL
)
1072 PRPN_STACK Stack
= (PRPN_STACK
)Expression
;
1074 ASSERT(Expression
!= NULL
);
1075 ASSERT(TrapFrame
!= NULL
);
1076 ASSERT(Result
!= NULL
);
1078 /* Evaluate the stack */
1079 return RpnpEvaluateStack(Stack
, TrapFrame
, Result
, ErrOffset
, ErrMsg
);