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