xref: /reactos/ntoskrnl/kdbg/kdb_expr.c (revision bd712186)
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 2005 ReactOS Team
4  *
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.
9  *
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.
14  *
15  *  You should have received a copy of the GNU General Public License along
16  *  with this program; if not, write to the Free Software Foundation, Inc.,
17  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 /*
20  * PROJECT:         ReactOS kernel
21  * FILE:            ntoskrnl/kdbg/kdb_expr.c
22  * PURPOSE:         Kernel debugger expression evaluation
23  * PROGRAMMER:      Gregor Anich (blight@blight.eu.org)
24  * UPDATE HISTORY:
25  *                  Created 15/01/2005
26  */
27 
28 /* Note:
29  *
30  * The given expression is parsed and stored in reverse polish notation,
31  * then it is evaluated and the result is returned.
32  */
33 
34 /* INCLUDES ******************************************************************/
35 
36 #include <ntoskrnl.h>
37 #define NDEBUG
38 #include <debug.h>
39 
40 /* TYPES *********************************************************************/
41 typedef enum _RPN_OP_TYPE
42 {
43     RpnOpNop,
44     RpnOpBinaryOperator,
45     RpnOpUnaryOperator,
46     RpnOpImmediate,
47     RpnOpRegister,
48     RpnOpDereference
49 } RPN_OP_TYPE;
50 
51 typedef ULONGLONG (*RPN_BINARY_OPERATOR)(ULONGLONG a, ULONGLONG b);
52 
53 typedef struct _RPN_OP
54 {
55     RPN_OP_TYPE  Type;
56     ULONG        CharacterOffset;
57     union
58     {
59         /* RpnOpBinaryOperator */
60         RPN_BINARY_OPERATOR  BinaryOperator;
61         /* RpnOpImmediate */
62         ULONGLONG            Immediate;
63         /* RpnOpRegister */
64         UCHAR                Register;
65         /* RpnOpDereference */
66         UCHAR                DerefMemorySize;
67     }
68     Data;
69 }
70 RPN_OP, *PRPN_OP;
71 
72 typedef struct _RPN_STACK
73 {
74     ULONG   Size;     /* Number of RPN_OPs on Ops */
75     ULONG   Sp;       /* Stack pointer */
76     RPN_OP  Ops[1];   /* Array of RPN_OPs */
77 }
78 RPN_STACK, *PRPN_STACK;
79 
80 /* DEFINES *******************************************************************/
81 #define stricmp _stricmp
82 
83 #ifndef RTL_FIELD_SIZE
84 # define RTL_FIELD_SIZE(type, field) (sizeof(((type *)0)->field))
85 #endif
86 
87 #define CONST_STRCPY(dst, src) \
88     do { if ((dst)) { memcpy(dst, src, sizeof(src)); } } while (0);
89 
90 #define RPN_OP_STACK_SIZE     256
91 #define RPN_VALUE_STACK_SIZE  256
92 
93 /* GLOBALS *******************************************************************/
94 static struct
95 {
96     ULONG Size;
97     ULONG Sp;
98     RPN_OP Ops[RPN_OP_STACK_SIZE];
99 }
100 RpnStack =
101 {
102     RPN_OP_STACK_SIZE,
103     0
104 };
105 
106 static const struct
107 {
108     PCHAR Name;
109     UCHAR Offset;
110     UCHAR Size;
111 }
112 RegisterToTrapFrame[] =
113 {
114     {"eip",     FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Eip),     RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Eip)},
115     {"eflags",  FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.EFlags),  RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.EFlags)},
116     {"eax",     FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Eax),     RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Eax)},
117     {"ebx",     FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Ebx),     RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Ebx)},
118     {"ecx",     FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Ecx),     RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Ecx)},
119     {"edx",     FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Edx),     RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Edx)},
120     {"esi",     FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Esi),     RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Esi)},
121     {"edi",     FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Edi),     RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Edi)},
122     {"esp",     FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.HardwareEsp),     RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.HardwareEsp)},
123     {"ebp",     FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Ebp),     RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Ebp)},
124     {"cs",      FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.SegCs),      2 }, /* Use only the lower 2 bytes */
125     {"ds",      FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.SegDs),      RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.SegDs)},
126     {"es",      FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.SegEs),      RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.SegEs)},
127     {"fs",      FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.SegFs),      RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.SegFs)},
128     {"gs",      FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.SegGs),      RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.SegGs)},
129     {"ss",      FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.HardwareSegSs),      RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.HardwareSegSs)},
130     {"dr0",     FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Dr0),     RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Dr0)},
131     {"dr1",     FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Dr1),     RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Dr1)},
132     {"dr2",     FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Dr2),     RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Dr2)},
133     {"dr3",     FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Dr3),     RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Dr3)},
134     {"dr6",     FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Dr6),     RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Dr6)},
135     {"dr7",     FIELD_OFFSET(KDB_KTRAP_FRAME, Tf.Dr7),     RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Tf.Dr7)},
136     {"cr0",     FIELD_OFFSET(KDB_KTRAP_FRAME, Cr0),        RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Cr0)},
137     {"cr2",     FIELD_OFFSET(KDB_KTRAP_FRAME, Cr2),        RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Cr2)},
138     {"cr3",     FIELD_OFFSET(KDB_KTRAP_FRAME, Cr3),        RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Cr3)},
139     {"cr4",     FIELD_OFFSET(KDB_KTRAP_FRAME, Cr4),        RTL_FIELD_SIZE(KDB_KTRAP_FRAME, Cr4)}
140 };
141 static const INT RegisterToTrapFrameCount = sizeof (RegisterToTrapFrame) / sizeof (RegisterToTrapFrame[0]);
142 
143 /* FUNCTIONS *****************************************************************/
144 
145 ULONGLONG
146 RpnBinaryOperatorAdd(
147     ULONGLONG a,
148     ULONGLONG b)
149 {
150     return a + b;
151 }
152 
153 ULONGLONG
154 RpnBinaryOperatorSub(
155     ULONGLONG a,
156     ULONGLONG b)
157 {
158     return a - b;
159 }
160 
161 ULONGLONG
162 RpnBinaryOperatorMul(
163     ULONGLONG a,
164     ULONGLONG b)
165 {
166     return a * b;
167 }
168 
169 ULONGLONG
170 RpnBinaryOperatorDiv(
171     ULONGLONG a,
172     ULONGLONG b)
173 {
174     return a / b;
175 }
176 
177 ULONGLONG
178 RpnBinaryOperatorMod(
179     ULONGLONG a,
180     ULONGLONG b)
181 {
182     return a % b;
183 }
184 
185 ULONGLONG
186 RpnBinaryOperatorEquals(
187     ULONGLONG a,
188     ULONGLONG b)
189 {
190     return (a == b);
191 }
192 
193 ULONGLONG
194 RpnBinaryOperatorNotEquals(
195     ULONGLONG a,
196     ULONGLONG b)
197 {
198     return (a != b);
199 }
200 
201 ULONGLONG
202 RpnBinaryOperatorLessThan(
203     ULONGLONG a,
204     ULONGLONG b)
205 {
206     return (a < b);
207 }
208 
209 ULONGLONG
210 RpnBinaryOperatorLessThanOrEquals(
211     ULONGLONG a,
212     ULONGLONG b)
213 {
214     return (a <= b);
215 }
216 
217 ULONGLONG
218 RpnBinaryOperatorGreaterThan(
219     ULONGLONG a,
220     ULONGLONG b)
221 {
222     return (a > b);
223 }
224 
225 ULONGLONG
226 RpnBinaryOperatorGreaterThanOrEquals(
227     ULONGLONG a,
228     ULONGLONG b)
229 {
230     return (a >= b);
231 }
232 
233 /*!\brief Dumps the given RPN stack content
234  *
235  * \param Stack  Pointer to a RPN_STACK structure.
236  */
237 VOID
238 RpnpDumpStack(
239     IN PRPN_STACK Stack)
240 {
241     ULONG ul;
242 
243     ASSERT(Stack);
244     DbgPrint("\nStack size: %ld\n", Stack->Sp);
245 
246     for (ul = 0; ul < Stack->Sp; ul++)
247     {
248         PRPN_OP Op = Stack->Ops + ul;
249         switch (Op->Type)
250         {
251             case RpnOpNop:
252                 DbgPrint("NOP,");
253                 break;
254 
255             case RpnOpImmediate:
256                 DbgPrint("0x%I64x,", Op->Data.Immediate);
257                 break;
258 
259             case RpnOpBinaryOperator:
260                 if (Op->Data.BinaryOperator == RpnBinaryOperatorAdd)
261                     DbgPrint("+,");
262                 else if (Op->Data.BinaryOperator == RpnBinaryOperatorSub)
263                     DbgPrint("-,");
264                 else if (Op->Data.BinaryOperator == RpnBinaryOperatorMul)
265                     DbgPrint("*,");
266                 else if (Op->Data.BinaryOperator == RpnBinaryOperatorDiv)
267                     DbgPrint("/,");
268                 else if (Op->Data.BinaryOperator == RpnBinaryOperatorMod)
269                     DbgPrint("%%,");
270                 else if (Op->Data.BinaryOperator == RpnBinaryOperatorEquals)
271                     DbgPrint("==,");
272                 else if (Op->Data.BinaryOperator == RpnBinaryOperatorNotEquals)
273                     DbgPrint("!=,");
274                 else if (Op->Data.BinaryOperator == RpnBinaryOperatorLessThan)
275                     DbgPrint("<,");
276                 else if (Op->Data.BinaryOperator == RpnBinaryOperatorLessThanOrEquals)
277                     DbgPrint("<=,");
278                 else if (Op->Data.BinaryOperator == RpnBinaryOperatorGreaterThan)
279                     DbgPrint(">,");
280                 else if (Op->Data.BinaryOperator == RpnBinaryOperatorGreaterThanOrEquals)
281                     DbgPrint(">=,");
282                 else
283                     DbgPrint("UNKNOWN OP,");
284 
285                 break;
286 
287             case RpnOpRegister:
288                 DbgPrint("%s,", RegisterToTrapFrame[Op->Data.Register].Name);
289                 break;
290 
291             case RpnOpDereference:
292                 DbgPrint("[%s],",
293                     (Op->Data.DerefMemorySize == 1) ? ("byte") :
294                     ((Op->Data.DerefMemorySize == 2) ? ("word") :
295                     ((Op->Data.DerefMemorySize == 4) ? ("dword") : ("qword"))));
296                 break;
297 
298             default:
299                 DbgPrint("\nUnsupported Type: %d\n", Op->Type);
300                 ul = Stack->Sp;
301                 break;
302         }
303     }
304 
305     DbgPrint("\n");
306 }
307 
308 /*!\brief Clears the given RPN stack.
309  *
310  * \param Stack  Pointer to a RPN_STACK structure.
311  */
312 static VOID
313 RpnpClearStack(
314     OUT PRPN_STACK Stack)
315 {
316     ASSERT(Stack);
317     Stack->Sp = 0;
318 }
319 
320 /*!\brief Pushes an RPN_OP onto the stack.
321  *
322  * \param Stack  Pointer to a RPN_STACK structure.
323  * \param Op     RPN_OP to be copied onto the stack.
324  */
325 static BOOLEAN
326 RpnpPushStack(
327     IN OUT PRPN_STACK Stack,
328     IN     PRPN_OP Op)
329 {
330     ASSERT(Stack);
331     ASSERT(Op);
332 
333     if (Stack->Sp >= Stack->Size)
334         return FALSE;
335 
336     memcpy(Stack->Ops + Stack->Sp, Op, sizeof (RPN_OP));
337     Stack->Sp++;
338 
339     return TRUE;
340 }
341 
342 /*!\brief Pops the top op from the stack.
343  *
344  * \param Stack  Pointer to a RPN_STACK structure.
345  * \param Op     Pointer to an RPN_OP to store the popped op into (can be NULL).
346  *
347  * \retval TRUE   Success.
348  * \retval FALSE  Failure (stack empty)
349  */
350 static BOOLEAN
351 RpnpPopStack(
352     IN OUT PRPN_STACK Stack,
353     OUT    PRPN_OP Op  OPTIONAL)
354 {
355     ASSERT(Stack);
356 
357     if (Stack->Sp == 0)
358         return FALSE;
359 
360     Stack->Sp--;
361     if (Op)
362         memcpy(Op, Stack->Ops + Stack->Sp, sizeof (RPN_OP));
363 
364     return TRUE;
365 }
366 
367 /*!\brief Gets the top op from the stack (not popping it)
368  *
369  * \param Stack  Pointer to a RPN_STACK structure.
370  * \param Op     Pointer to an RPN_OP to copy the top op into.
371  *
372  * \retval TRUE   Success.
373  * \retval FALSE  Failure (stack empty)
374  */
375 static BOOLEAN
376 RpnpTopStack(
377     IN  PRPN_STACK Stack,
378     OUT PRPN_OP Op)
379 {
380     ASSERT(Stack);
381     ASSERT(Op);
382 
383     if (Stack->Sp == 0)
384         return FALSE;
385 
386     memcpy(Op, Stack->Ops + Stack->Sp - 1, sizeof (RPN_OP));
387 
388     return TRUE;
389 }
390 
391 /*!\brief Parses an expression.
392  *
393  * This functions parses the given expression until the end of string or a closing
394  * brace is found. As the function parses the string it pushes RPN_OPs onto the
395  * stack.
396  *
397  * Examples: 1+2*3 ; eax+10 ; (eax+16) * (ebx+4) ; dword[eax]
398  *
399  * \param Stack            Pointer to a RPN_STACK structure.
400  * \param Expression       String to parse.
401  * \param CharacterOffset  Character offset of the subexpression from the beginning of the expression.
402  * \param End              On success End is set to the character at which parsing stopped.
403  * \param ErrOffset        On failure this is set to the character offset at which the error occoured.
404  * \param ErrMsg           On failure a message describing the problem is copied into this buffer (128 bytes)
405  *
406  * \retval TRUE   Success.
407  * \retval FALSE  Failure.
408  */
409 static BOOLEAN
410 RpnpParseExpression(
411     IN  PRPN_STACK Stack,
412     IN  PCHAR Expression,
413     OUT PCHAR *End  OPTIONAL,
414     IN  ULONG CharacterOffset,
415     OUT PLONG ErrOffset  OPTIONAL,
416     OUT PCHAR ErrMsg  OPTIONAL)
417 {
418     PCHAR p = Expression;
419     PCHAR pend;
420     PCHAR Operator = NULL;
421     LONG OperatorOffset = -1;
422     RPN_OP RpnOp;
423     RPN_OP PoppedOperator;
424     BOOLEAN HavePoppedOperator = FALSE;
425     RPN_OP ComparativeOp;
426     BOOLEAN ComparativeOpFilled = FALSE;
427     BOOLEAN IsComparativeOp;
428     INT i, i2;
429     ULONG ul;
430     UCHAR MemorySize;
431     CHAR Buffer[16];
432     BOOLEAN First;
433 
434     ASSERT(Stack);
435     ASSERT(Expression);
436 
437     First = TRUE;
438     for (;;)
439     {
440         /* Skip whitespace */
441         while (isspace(*p))
442         {
443             p++;
444             CharacterOffset++;
445         }
446 
447         /* Check for end of expression */
448         if (p[0] == '\0' || p[0] == ')' || p[0] == ']')
449             break;
450 
451         if (!First)
452         {
453             /* Remember operator */
454             Operator = p++;
455             OperatorOffset = CharacterOffset++;
456 
457             /* Pop operator (to get the right operator precedence) */
458             HavePoppedOperator = FALSE;
459             if (*Operator == '*' || *Operator == '/' || *Operator == '%')
460             {
461                 if (RpnpTopStack(Stack, &PoppedOperator) &&
462                     PoppedOperator.Type == RpnOpBinaryOperator &&
463                     (PoppedOperator.Data.BinaryOperator == RpnBinaryOperatorAdd ||
464                     PoppedOperator.Data.BinaryOperator == RpnBinaryOperatorSub))
465                 {
466                     RpnpPopStack(Stack, NULL);
467                     HavePoppedOperator = TRUE;
468                 }
469                 else if (PoppedOperator.Type == RpnOpNop)
470                 {
471                     RpnpPopStack(Stack, NULL);
472                     /* Discard the NOP - it was only pushed to indicate there was a
473                      * closing brace, so the previous operator shouldn't be popped.
474                      */
475                 }
476             }
477             else if ((Operator[0] == '=' && Operator[1] == '=') ||
478                      (Operator[0] == '!' && Operator[1] == '=') ||
479                      Operator[0] == '<' || Operator[0] == '>')
480             {
481                 if (Operator[0] == '=' || Operator[0] == '!' ||
482                     (Operator[0] == '<' && Operator[1] == '=') ||
483                     (Operator[0] == '>' && Operator[1] == '='))
484                 {
485                     p++;
486                     CharacterOffset++;
487                 }
488 #if 0
489                 /* Parse rest of expression */
490                 if (!RpnpParseExpression(Stack, p + 1, &pend, CharacterOffset + 1,
491                                          ErrOffset, ErrMsg))
492                 {
493                     return FALSE;
494                 }
495                 else if (pend == p + 1)
496                 {
497                     CONST_STRCPY(ErrMsg, "Expression expected");
498 
499                     if (ErrOffset)
500                         *ErrOffset = CharacterOffset + 1;
501 
502                     return FALSE;
503                 }
504 
505                 goto end_of_expression; /* return */
506 #endif
507             }
508             else if (Operator[0] != '+' && Operator[0] != '-')
509             {
510                 CONST_STRCPY(ErrMsg, "Operator expected");
511 
512                 if (ErrOffset)
513                     *ErrOffset = OperatorOffset;
514 
515                 return FALSE;
516             }
517 
518             /* Skip whitespace */
519             while (isspace(*p))
520             {
521                 p++;
522                 CharacterOffset++;
523             }
524         }
525 
526         /* Get operand */
527         MemorySize = sizeof(ULONG_PTR); /* default to pointer size */
528 
529 get_operand:
530         i = strcspn(p, "+-*/%()[]<>!=");
531         if (i > 0)
532         {
533             i2 = i;
534 
535             /* Copy register name/memory size */
536             while (isspace(p[--i2]));
537 
538             i2 = min(i2 + 1, (INT)sizeof (Buffer) - 1);
539             strncpy(Buffer, p, i2);
540             Buffer[i2] = '\0';
541 
542             /* Memory size prefix */
543             if (p[i] == '[')
544             {
545                 if (stricmp(Buffer, "byte") == 0)
546                     MemorySize = 1;
547                 else if (stricmp(Buffer, "word") == 0)
548                     MemorySize = 2;
549                 else if (stricmp(Buffer, "dword") == 0)
550                     MemorySize = 4;
551                 else if (stricmp(Buffer, "qword") == 0)
552                     MemorySize = 8;
553                 else
554                 {
555                     CONST_STRCPY(ErrMsg, "Invalid memory size prefix");
556 
557                     if (ErrOffset)
558                         *ErrOffset = CharacterOffset;
559 
560                     return FALSE;
561                 }
562 
563                 p += i;
564                 CharacterOffset += i;
565                 goto get_operand;
566             }
567 
568             /* Try to find register */
569             for (i = 0; i < RegisterToTrapFrameCount; i++)
570             {
571                 if (stricmp(RegisterToTrapFrame[i].Name, Buffer) == 0)
572                     break;
573             }
574 
575             if (i < RegisterToTrapFrameCount)
576             {
577                 RpnOp.Type = RpnOpRegister;
578                 RpnOp.CharacterOffset = CharacterOffset;
579                 RpnOp.Data.Register = i;
580                 i = strlen(RegisterToTrapFrame[i].Name);
581                 CharacterOffset += i;
582                 p += i;
583             }
584             else
585             {
586                 /* Immediate value */
587                 /* FIXME: Need string to ULONGLONG function */
588                 ul = strtoul(p, &pend, 0);
589                 if (p != pend)
590                 {
591                     RpnOp.Type = RpnOpImmediate;
592                     RpnOp.CharacterOffset = CharacterOffset;
593                     RpnOp.Data.Immediate = (ULONGLONG)ul;
594                     CharacterOffset += pend - p;
595                     p = pend;
596                 }
597                 else
598                 {
599                     CONST_STRCPY(ErrMsg, "Operand expected");
600 
601                     if (ErrOffset)
602                         *ErrOffset = CharacterOffset;
603 
604                     return FALSE;
605                 }
606             }
607 
608             /* Push operand */
609             if (!RpnpPushStack(Stack, &RpnOp))
610             {
611                 CONST_STRCPY(ErrMsg, "RPN op stack overflow");
612 
613                 if (ErrOffset)
614                     *ErrOffset = -1;
615 
616                 return FALSE;
617             }
618         }
619         else if (i == 0)
620         {
621             if (p[0] == '(' || p[0] == '[') /* subexpression */
622             {
623                 if (!RpnpParseExpression(Stack, p + 1, &pend, CharacterOffset + 1,
624                                          ErrOffset, ErrMsg))
625                 {
626                     return FALSE;
627                 }
628                 else if (pend == p + 1)
629                 {
630                     CONST_STRCPY(ErrMsg, "Expression expected");
631 
632                     if (ErrOffset)
633                         *ErrOffset = CharacterOffset + 1;
634 
635                     return FALSE;
636                 }
637 
638                 if (p[0] == '[') /* dereference */
639                 {
640                     ASSERT(MemorySize == 1 || MemorySize == 2 ||
641                            MemorySize == 4 || MemorySize == 8);
642 
643                     if (pend[0] != ']')
644                     {
645                         CONST_STRCPY(ErrMsg, "']' expected");
646 
647                         if (ErrOffset)
648                             *ErrOffset = CharacterOffset + (pend - p);
649 
650                         return FALSE;
651                     }
652 
653                     RpnOp.Type = RpnOpDereference;
654                     RpnOp.CharacterOffset = CharacterOffset;
655                     RpnOp.Data.DerefMemorySize = MemorySize;
656 
657                     if (!RpnpPushStack(Stack, &RpnOp))
658                     {
659                         CONST_STRCPY(ErrMsg, "RPN op stack overflow");
660 
661                         if (ErrOffset)
662                             *ErrOffset = -1;
663 
664                         return FALSE;
665                     }
666                 }
667                 else /* p[0] == '(' */
668                 {
669                     if (pend[0] != ')')
670                     {
671                         CONST_STRCPY(ErrMsg, "')' expected");
672 
673                         if (ErrOffset)
674                             *ErrOffset = CharacterOffset + (pend - p);
675 
676                         return FALSE;
677                     }
678                 }
679 
680                 /* Push a "nop" to prevent popping of the + operator (which would
681                  * result in (10+10)/2 beeing evaluated as 15)
682                  */
683                 RpnOp.Type = RpnOpNop;
684                 if (!RpnpPushStack(Stack, &RpnOp))
685                 {
686                     CONST_STRCPY(ErrMsg, "RPN op stack overflow");
687 
688                     if (ErrOffset)
689                         *ErrOffset = -1;
690 
691                     return FALSE;
692                 }
693 
694                 /* Skip closing brace/bracket */
695                 pend++;
696 
697                 CharacterOffset += pend - p;
698                 p = pend;
699             }
700             else if (First && p[0] == '-') /* Allow expressions like "- eax" */
701             {
702                 RpnOp.Type = RpnOpImmediate;
703                 RpnOp.CharacterOffset = CharacterOffset;
704                 RpnOp.Data.Immediate = 0;
705 
706                 if (!RpnpPushStack(Stack, &RpnOp))
707                 {
708                     CONST_STRCPY(ErrMsg, "RPN op stack overflow");
709 
710                     if (ErrOffset)
711                         *ErrOffset = -1;
712 
713                     return FALSE;
714                 }
715             }
716             else
717             {
718                 CONST_STRCPY(ErrMsg, "Operand expected");
719 
720                 if (ErrOffset)
721                     *ErrOffset = CharacterOffset;
722 
723                 return FALSE;
724             }
725         }
726         else
727         {
728             CONST_STRCPY(ErrMsg, "strcspn() failed");
729 
730             if (ErrOffset)
731                 *ErrOffset = -1;
732 
733             return FALSE;
734         }
735 
736         if (!First)
737         {
738             /* Push operator */
739             RpnOp.CharacterOffset = OperatorOffset;
740             RpnOp.Type = RpnOpBinaryOperator;
741             IsComparativeOp = FALSE;
742 
743             switch (*Operator)
744             {
745                 case '+':
746                     RpnOp.Data.BinaryOperator = RpnBinaryOperatorAdd;
747                     break;
748 
749                 case '-':
750                     RpnOp.Data.BinaryOperator = RpnBinaryOperatorSub;
751                     break;
752 
753                 case '*':
754                     RpnOp.Data.BinaryOperator = RpnBinaryOperatorMul;
755                     break;
756 
757                 case '/':
758                     RpnOp.Data.BinaryOperator = RpnBinaryOperatorDiv;
759                     break;
760 
761                 case '%':
762                     RpnOp.Data.BinaryOperator = RpnBinaryOperatorMod;
763                     break;
764 
765                 case '=':
766                     ASSERT(Operator[1] == '=');
767                     IsComparativeOp = TRUE;
768                     RpnOp.Data.BinaryOperator = RpnBinaryOperatorEquals;
769                     break;
770 
771                 case '!':
772                     ASSERT(Operator[1] == '=');
773                     IsComparativeOp = TRUE;
774                     RpnOp.Data.BinaryOperator = RpnBinaryOperatorNotEquals;
775                     break;
776 
777                 case '<':
778                     IsComparativeOp = TRUE;
779 
780                     if (Operator[1] == '=')
781                         RpnOp.Data.BinaryOperator = RpnBinaryOperatorLessThanOrEquals;
782                     else
783                         RpnOp.Data.BinaryOperator = RpnBinaryOperatorLessThan;
784 
785                     break;
786 
787                 case '>':
788                     IsComparativeOp = TRUE;
789 
790                     if (Operator[1] == '=')
791                         RpnOp.Data.BinaryOperator = RpnBinaryOperatorGreaterThanOrEquals;
792                     else
793                         RpnOp.Data.BinaryOperator = RpnBinaryOperatorGreaterThan;
794 
795                     break;
796 
797                 default:
798                     ASSERT(0);
799                     break;
800             }
801 
802             if (IsComparativeOp)
803             {
804                 if (ComparativeOpFilled && !RpnpPushStack(Stack, &ComparativeOp))
805                 {
806                     CONST_STRCPY(ErrMsg, "RPN op stack overflow");
807 
808                     if (ErrOffset)
809                         *ErrOffset = -1;
810 
811                     return FALSE;
812                 }
813 
814                 memcpy(&ComparativeOp, &RpnOp, sizeof(RPN_OP));
815                 ComparativeOpFilled = TRUE;
816             }
817             else if (!RpnpPushStack(Stack, &RpnOp))
818             {
819                 CONST_STRCPY(ErrMsg, "RPN op stack overflow");
820 
821                 if (ErrOffset)
822                     *ErrOffset = -1;
823 
824                 return FALSE;
825             }
826 
827             /* Push popped operator */
828             if (HavePoppedOperator)
829             {
830                 if (!RpnpPushStack(Stack, &PoppedOperator))
831                 {
832                     CONST_STRCPY(ErrMsg, "RPN op stack overflow");
833 
834                     if (ErrOffset)
835                         *ErrOffset = -1;
836 
837                     return FALSE;
838                 }
839             }
840         }
841 
842         First = FALSE;
843     }
844 
845 //end_of_expression:
846 
847     if (ComparativeOpFilled && !RpnpPushStack(Stack, &ComparativeOp))
848     {
849         CONST_STRCPY(ErrMsg, "RPN op stack overflow");
850 
851         if (ErrOffset)
852             *ErrOffset = -1;
853 
854         return FALSE;
855     }
856 
857     /* Skip whitespace */
858     while (isspace(*p))
859     {
860         p++;
861         CharacterOffset++;
862     }
863 
864     if (End)
865         *End = p;
866 
867     return TRUE;
868 }
869 
870 /*!\brief Evaluates the RPN op stack and returns the result.
871  *
872  * \param Stack      Pointer to a RPN_STACK structure.
873  * \param TrapFrame  Register values.
874  * \param Result     Pointer to an ULONG to store the result into.
875  * \param ErrOffset  On failure this is set to the character offset at which the error occoured.
876  * \param ErrMsg     Buffer which receives an error message on failure (128 bytes)
877  *
878  * \retval TRUE   Success.
879  * \retval FALSE  Failure.
880  */
881 static BOOLEAN
882 RpnpEvaluateStack(
883     IN  PRPN_STACK Stack,
884     IN  PKDB_KTRAP_FRAME TrapFrame,
885     OUT PULONGLONG Result,
886     OUT PLONG ErrOffset  OPTIONAL,
887     OUT PCHAR ErrMsg  OPTIONAL)
888 {
889     ULONGLONG ValueStack[RPN_VALUE_STACK_SIZE];
890     ULONG ValueStackPointer = 0;
891     ULONG index;
892     ULONGLONG ull;
893     ULONG ul;
894     USHORT us;
895     UCHAR uc;
896     PVOID p;
897     BOOLEAN Ok;
898 #ifdef DEBUG_RPN
899     ULONG ValueStackPointerMax = 0;
900 #endif
901 
902     ASSERT(Stack);
903     ASSERT(TrapFrame);
904     ASSERT(Result);
905 
906     for (index = 0; index < Stack->Sp; index++)
907     {
908         PRPN_OP Op = Stack->Ops + index;
909 
910 #ifdef DEBUG_RPN
911         ValueStackPointerMax = max(ValueStackPointerMax, ValueStackPointer);
912 #endif
913 
914         switch (Op->Type)
915         {
916             case RpnOpNop:
917                 /* No operation */
918                 break;
919 
920             case RpnOpImmediate:
921                 if (ValueStackPointer == RPN_VALUE_STACK_SIZE)
922                 {
923                     CONST_STRCPY(ErrMsg, "Value stack overflow");
924 
925                     if (ErrOffset)
926                         *ErrOffset = -1;
927 
928                     return FALSE;
929                 }
930 
931                 ValueStack[ValueStackPointer++] = Op->Data.Immediate;
932                 break;
933 
934             case RpnOpRegister:
935                 if (ValueStackPointer == RPN_VALUE_STACK_SIZE)
936                 {
937                     CONST_STRCPY(ErrMsg, "Value stack overflow");
938 
939                     if (ErrOffset)
940                         *ErrOffset = -1;
941 
942                     return FALSE;
943                 }
944 
945                 ul = Op->Data.Register;
946                 p = (PVOID)((ULONG_PTR)TrapFrame + RegisterToTrapFrame[ul].Offset);
947 
948                 switch (RegisterToTrapFrame[ul].Size)
949                 {
950                     case 1: ull = (ULONGLONG)(*(PUCHAR)p); break;
951                     case 2: ull = (ULONGLONG)(*(PUSHORT)p); break;
952                     case 4: ull = (ULONGLONG)(*(PULONG)p); break;
953                     case 8: ull = (ULONGLONG)(*(PULONGLONG)p); break;
954                     default: ASSERT(0); return FALSE; break;
955                 }
956 
957                 ValueStack[ValueStackPointer++] = ull;
958                 break;
959 
960             case RpnOpDereference:
961                 if (ValueStackPointer < 1)
962                 {
963                     CONST_STRCPY(ErrMsg, "Value stack underflow");
964 
965                     if (ErrOffset)
966                         *ErrOffset = -1;
967 
968                     return FALSE;
969                 }
970 
971                 /* FIXME: Print a warning when address is out of range */
972                 p = (PVOID)(ULONG_PTR)ValueStack[ValueStackPointer - 1];
973                 Ok = FALSE;
974 
975                 switch (Op->Data.DerefMemorySize)
976                 {
977                     case 1:
978                         if (NT_SUCCESS(KdbpSafeReadMemory(&uc, p, sizeof (uc))))
979                         {
980                             Ok = TRUE;
981                             ull = (ULONGLONG)uc;
982                         }
983                         break;
984 
985                     case 2:
986                         if (NT_SUCCESS(KdbpSafeReadMemory(&us, p, sizeof (us))))
987                         {
988                             Ok = TRUE;
989                             ull = (ULONGLONG)us;
990                         }
991                         break;
992 
993                     case 4:
994                         if (NT_SUCCESS(KdbpSafeReadMemory(&ul, p, sizeof (ul))))
995                         {
996                             Ok = TRUE;
997                             ull = (ULONGLONG)ul;
998                         }
999                         break;
1000 
1001                     case 8:
1002                         if (NT_SUCCESS(KdbpSafeReadMemory(&ull, p, sizeof (ull))))
1003                         {
1004                             Ok = TRUE;
1005                         }
1006                         break;
1007 
1008                     default:
1009                         ASSERT(0);
1010                         return FALSE;
1011                         break;
1012                 }
1013 
1014                 if (!Ok)
1015                 {
1016                     _snprintf(ErrMsg, 128, "Couldn't access memory at 0x%lx", (ULONG)p);
1017 
1018                     if (ErrOffset)
1019                         *ErrOffset = Op->CharacterOffset;
1020 
1021                     return FALSE;
1022                 }
1023 
1024                 ValueStack[ValueStackPointer - 1] = ull;
1025                 break;
1026 
1027             case RpnOpBinaryOperator:
1028                 if (ValueStackPointer < 2)
1029                 {
1030                     CONST_STRCPY(ErrMsg, "Value stack underflow");
1031 
1032                     if (ErrOffset)
1033                         *ErrOffset = -1;
1034 
1035                     return FALSE;
1036                 }
1037 
1038                 ValueStackPointer--;
1039                 ull = ValueStack[ValueStackPointer];
1040 
1041                 if (ull == 0 && Op->Data.BinaryOperator == RpnBinaryOperatorDiv)
1042                 {
1043                     CONST_STRCPY(ErrMsg, "Division by zero");
1044 
1045                     if (ErrOffset)
1046                         *ErrOffset = Op->CharacterOffset;
1047 
1048                     return FALSE;
1049                 }
1050 
1051                 ull = Op->Data.BinaryOperator(ValueStack[ValueStackPointer - 1], ull);
1052                 ValueStack[ValueStackPointer - 1] = ull;
1053                 break;
1054 
1055             default:
1056                 ASSERT(0);
1057                 return FALSE;
1058         }
1059     }
1060 
1061 #ifdef DEBUG_RPN
1062     DPRINT1("Max value stack pointer: %d\n", ValueStackPointerMax);
1063 #endif
1064 
1065     if (ValueStackPointer != 1)
1066     {
1067         CONST_STRCPY(ErrMsg, "Stack not empty after evaluation");
1068 
1069         if (ErrOffset)
1070             *ErrOffset = -1;
1071 
1072         return FALSE;
1073     }
1074 
1075     *Result = ValueStack[0];
1076     return TRUE;
1077 }
1078 
1079 /*!\brief Evaluates the given expression
1080  *
1081  * \param Expression  Expression to evaluate.
1082  * \param TrapFrame   Register values.
1083  * \param Result      Variable which receives the result on success.
1084  * \param ErrOffset   Variable which receives character offset on parse error (-1 on other errors)
1085  * \param ErrMsg      Buffer which receives an error message on failure (128 bytes)
1086  *
1087  * \retval TRUE   Success.
1088  * \retval FALSE  Failure.
1089  */
1090 BOOLEAN
1091 KdbpRpnEvaluateExpression(
1092     IN  PCHAR Expression,
1093     IN  PKDB_KTRAP_FRAME TrapFrame,
1094     OUT PULONGLONG Result,
1095     OUT PLONG ErrOffset  OPTIONAL,
1096     OUT PCHAR ErrMsg  OPTIONAL)
1097 {
1098     PRPN_STACK Stack = (PRPN_STACK)&RpnStack;
1099 
1100     ASSERT(Expression);
1101     ASSERT(TrapFrame);
1102     ASSERT(Result);
1103 
1104     /* Clear the stack and parse the expression */
1105     RpnpClearStack(Stack);
1106     if (!RpnpParseExpression(Stack, Expression, NULL, 0, ErrOffset, ErrMsg))
1107         return FALSE;
1108 
1109 #ifdef DEBUG_RPN
1110     RpnpDumpStack(Stack);
1111 #endif
1112 
1113     /* Evaluate the stack */
1114     if (!RpnpEvaluateStack(Stack, TrapFrame, Result, ErrOffset, ErrMsg))
1115         return FALSE;
1116 
1117     return TRUE;
1118 }
1119 
1120 /*!\brief Parses the given expression and returns a "handle" to it.
1121  *
1122  * \param Expression  Expression to evaluate.
1123  * \param ErrOffset   Variable which receives character offset on parse error (-1 on other errors)
1124  * \param ErrMsg      Buffer which receives an error message on failure (128 bytes)
1125  *
1126  * \returns "Handle" for the expression, NULL on failure.
1127  *
1128  * \sa KdbpRpnEvaluateExpression
1129  */
1130 PVOID
1131 KdbpRpnParseExpression(
1132     IN  PCHAR Expression,
1133     OUT PLONG ErrOffset  OPTIONAL,
1134     OUT PCHAR ErrMsg  OPTIONAL)
1135 {
1136     LONG Size;
1137     PRPN_STACK Stack = (PRPN_STACK)&RpnStack;
1138     PRPN_STACK NewStack;
1139 
1140     ASSERT(Expression);
1141 
1142     /* Clear the stack and parse the expression */
1143     RpnpClearStack(Stack);
1144     if (!RpnpParseExpression(Stack, Expression, NULL, 0, ErrOffset, ErrMsg))
1145         return FALSE;
1146 
1147 #ifdef DEBUG_RPN
1148     RpnpDumpStack(Stack);
1149 #endif
1150 
1151     /* Duplicate the stack and return a pointer/handle to it */
1152     ASSERT(Stack->Sp >= 1);
1153     Size = sizeof (RPN_STACK) + (RTL_FIELD_SIZE(RPN_STACK, Ops[0]) * (Stack->Sp - 1));
1154     NewStack = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_KDBG);
1155 
1156     if (!NewStack)
1157     {
1158         CONST_STRCPY(ErrMsg, "Out of memory");
1159 
1160         if (ErrOffset)
1161             *ErrOffset = -1;
1162 
1163         return NULL;
1164     }
1165 
1166     memcpy(NewStack, Stack, Size);
1167     NewStack->Size = NewStack->Sp;
1168 
1169     return NewStack;
1170 }
1171 
1172 /*!\brief Evaluates the given expression and returns the result.
1173  *
1174  * \param Expression  Expression "handle" returned by KdbpRpnParseExpression.
1175  * \param TrapFrame   Register values.
1176  * \param Result      Variable which receives the result on success.
1177  * \param ErrOffset   Variable which receives character offset on parse error (-1 on other errors)
1178  * \param ErrMsg      Buffer which receives an error message on failure (128 bytes)
1179  *
1180  * \returns "Handle" for the expression, NULL on failure.
1181  *
1182  * \sa KdbpRpnParseExpression
1183  */
1184 BOOLEAN
1185 KdbpRpnEvaluateParsedExpression(
1186     IN  PVOID Expression,
1187     IN  PKDB_KTRAP_FRAME TrapFrame,
1188     OUT PULONGLONG Result,
1189     OUT PLONG ErrOffset  OPTIONAL,
1190     OUT PCHAR ErrMsg  OPTIONAL)
1191 {
1192     PRPN_STACK Stack = (PRPN_STACK)Expression;
1193 
1194     ASSERT(Expression);
1195     ASSERT(TrapFrame);
1196     ASSERT(Result);
1197 
1198     /* Evaluate the stack */
1199     return RpnpEvaluateStack(Stack, TrapFrame, Result, ErrOffset, ErrMsg);
1200 }
1201 
1202