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