xref: /reactos/ntoskrnl/kdbg/kdb_expr.c (revision 3bd82236)
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_PTR i, i2;
441     ULONG64 ull;
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                 ull = strtoull(p, &pend, 0);
600                 if (p != pend)
601                 {
602                     RpnOp.Type = RpnOpImmediate;
603                     RpnOp.CharacterOffset = CharacterOffset;
604                     RpnOp.Data.Immediate = ull;
605                     CharacterOffset += pend - p;
606                     p = pend;
607                 }
608                 else
609                 {
610                     CONST_STRCPY(ErrMsg, "Operand expected");
611 
612                     if (ErrOffset)
613                         *ErrOffset = CharacterOffset;
614 
615                     return FALSE;
616                 }
617             }
618 
619             /* Push operand */
620             if (!RpnpPushStack(Stack, &RpnOp))
621             {
622                 CONST_STRCPY(ErrMsg, "RPN op stack overflow");
623 
624                 if (ErrOffset)
625                     *ErrOffset = -1;
626 
627                 return FALSE;
628             }
629         }
630         else if (i == 0)
631         {
632             if (p[0] == '(' || p[0] == '[') /* subexpression */
633             {
634                 if (!RpnpParseExpression(Stack, p + 1, &pend, CharacterOffset + 1,
635                                          ErrOffset, ErrMsg))
636                 {
637                     return FALSE;
638                 }
639                 else if (pend == p + 1)
640                 {
641                     CONST_STRCPY(ErrMsg, "Expression expected");
642 
643                     if (ErrOffset)
644                         *ErrOffset = CharacterOffset + 1;
645 
646                     return FALSE;
647                 }
648 
649                 if (p[0] == '[') /* dereference */
650                 {
651                     ASSERT(MemorySize == 1 || MemorySize == 2 ||
652                            MemorySize == 4 || MemorySize == 8);
653 
654                     if (pend[0] != ']')
655                     {
656                         CONST_STRCPY(ErrMsg, "']' expected");
657 
658                         if (ErrOffset)
659                             *ErrOffset = CharacterOffset + (pend - p);
660 
661                         return FALSE;
662                     }
663 
664                     RpnOp.Type = RpnOpDereference;
665                     RpnOp.CharacterOffset = CharacterOffset;
666                     RpnOp.Data.DerefMemorySize = MemorySize;
667 
668                     if (!RpnpPushStack(Stack, &RpnOp))
669                     {
670                         CONST_STRCPY(ErrMsg, "RPN op stack overflow");
671 
672                         if (ErrOffset)
673                             *ErrOffset = -1;
674 
675                         return FALSE;
676                     }
677                 }
678                 else /* p[0] == '(' */
679                 {
680                     if (pend[0] != ')')
681                     {
682                         CONST_STRCPY(ErrMsg, "')' expected");
683 
684                         if (ErrOffset)
685                             *ErrOffset = CharacterOffset + (pend - p);
686 
687                         return FALSE;
688                     }
689                 }
690 
691                 /* Push a "nop" to prevent popping of the + operator (which would
692                  * result in (10+10)/2 beeing evaluated as 15)
693                  */
694                 RpnOp.Type = RpnOpNop;
695                 if (!RpnpPushStack(Stack, &RpnOp))
696                 {
697                     CONST_STRCPY(ErrMsg, "RPN op stack overflow");
698 
699                     if (ErrOffset)
700                         *ErrOffset = -1;
701 
702                     return FALSE;
703                 }
704 
705                 /* Skip closing brace/bracket */
706                 pend++;
707 
708                 CharacterOffset += pend - p;
709                 p = pend;
710             }
711             else if (First && p[0] == '-') /* Allow expressions like "- eax" */
712             {
713                 RpnOp.Type = RpnOpImmediate;
714                 RpnOp.CharacterOffset = CharacterOffset;
715                 RpnOp.Data.Immediate = 0;
716 
717                 if (!RpnpPushStack(Stack, &RpnOp))
718                 {
719                     CONST_STRCPY(ErrMsg, "RPN op stack overflow");
720 
721                     if (ErrOffset)
722                         *ErrOffset = -1;
723 
724                     return FALSE;
725                 }
726             }
727             else
728             {
729                 CONST_STRCPY(ErrMsg, "Operand expected");
730 
731                 if (ErrOffset)
732                     *ErrOffset = CharacterOffset;
733 
734                 return FALSE;
735             }
736         }
737         else
738         {
739             CONST_STRCPY(ErrMsg, "strcspn() failed");
740 
741             if (ErrOffset)
742                 *ErrOffset = -1;
743 
744             return FALSE;
745         }
746 
747         if (!First)
748         {
749             /* Push operator */
750             RpnOp.CharacterOffset = OperatorOffset;
751             RpnOp.Type = RpnOpBinaryOperator;
752             IsComparativeOp = FALSE;
753 
754             switch (*Operator)
755             {
756                 case '+':
757                     RpnOp.Data.BinaryOperator = RpnBinaryOperatorAdd;
758                     break;
759 
760                 case '-':
761                     RpnOp.Data.BinaryOperator = RpnBinaryOperatorSub;
762                     break;
763 
764                 case '*':
765                     RpnOp.Data.BinaryOperator = RpnBinaryOperatorMul;
766                     break;
767 
768                 case '/':
769                     RpnOp.Data.BinaryOperator = RpnBinaryOperatorDiv;
770                     break;
771 
772                 case '%':
773                     RpnOp.Data.BinaryOperator = RpnBinaryOperatorMod;
774                     break;
775 
776                 case '=':
777                     ASSERT(Operator[1] == '=');
778                     IsComparativeOp = TRUE;
779                     RpnOp.Data.BinaryOperator = RpnBinaryOperatorEquals;
780                     break;
781 
782                 case '!':
783                     ASSERT(Operator[1] == '=');
784                     IsComparativeOp = TRUE;
785                     RpnOp.Data.BinaryOperator = RpnBinaryOperatorNotEquals;
786                     break;
787 
788                 case '<':
789                     IsComparativeOp = TRUE;
790 
791                     if (Operator[1] == '=')
792                         RpnOp.Data.BinaryOperator = RpnBinaryOperatorLessThanOrEquals;
793                     else
794                         RpnOp.Data.BinaryOperator = RpnBinaryOperatorLessThan;
795 
796                     break;
797 
798                 case '>':
799                     IsComparativeOp = TRUE;
800 
801                     if (Operator[1] == '=')
802                         RpnOp.Data.BinaryOperator = RpnBinaryOperatorGreaterThanOrEquals;
803                     else
804                         RpnOp.Data.BinaryOperator = RpnBinaryOperatorGreaterThan;
805 
806                     break;
807 
808                 default:
809                     ASSERT(0);
810                     break;
811             }
812 
813             if (IsComparativeOp)
814             {
815                 if (ComparativeOpFilled && !RpnpPushStack(Stack, &ComparativeOp))
816                 {
817                     CONST_STRCPY(ErrMsg, "RPN op stack overflow");
818 
819                     if (ErrOffset)
820                         *ErrOffset = -1;
821 
822                     return FALSE;
823                 }
824 
825                 memcpy(&ComparativeOp, &RpnOp, sizeof(RPN_OP));
826                 ComparativeOpFilled = TRUE;
827             }
828             else if (!RpnpPushStack(Stack, &RpnOp))
829             {
830                 CONST_STRCPY(ErrMsg, "RPN op stack overflow");
831 
832                 if (ErrOffset)
833                     *ErrOffset = -1;
834 
835                 return FALSE;
836             }
837 
838             /* Push popped operator */
839             if (HavePoppedOperator)
840             {
841                 if (!RpnpPushStack(Stack, &PoppedOperator))
842                 {
843                     CONST_STRCPY(ErrMsg, "RPN op stack overflow");
844 
845                     if (ErrOffset)
846                         *ErrOffset = -1;
847 
848                     return FALSE;
849                 }
850             }
851         }
852 
853         First = FALSE;
854     }
855 
856 //end_of_expression:
857 
858     if (ComparativeOpFilled && !RpnpPushStack(Stack, &ComparativeOp))
859     {
860         CONST_STRCPY(ErrMsg, "RPN op stack overflow");
861 
862         if (ErrOffset)
863             *ErrOffset = -1;
864 
865         return FALSE;
866     }
867 
868     /* Skip whitespace */
869     while (isspace(*p))
870     {
871         p++;
872         CharacterOffset++;
873     }
874 
875     if (End)
876         *End = p;
877 
878     return TRUE;
879 }
880 
881 /*!\brief Evaluates the RPN op stack and returns the result.
882  *
883  * \param Stack      Pointer to a RPN_STACK structure.
884  * \param TrapFrame  Register values.
885  * \param Result     Pointer to an ULONG to store the result into.
886  * \param ErrOffset  On failure this is set to the character offset at which the error occoured.
887  * \param ErrMsg     Buffer which receives an error message on failure (128 bytes)
888  *
889  * \retval TRUE   Success.
890  * \retval FALSE  Failure.
891  */
892 static BOOLEAN
893 RpnpEvaluateStack(
894     IN  PRPN_STACK Stack,
895     IN  PKDB_KTRAP_FRAME TrapFrame,
896     OUT PULONGLONG Result,
897     OUT PLONG ErrOffset  OPTIONAL,
898     OUT PCHAR ErrMsg  OPTIONAL)
899 {
900     ULONGLONG ValueStack[RPN_VALUE_STACK_SIZE];
901     ULONG ValueStackPointer = 0;
902     ULONG index;
903     ULONGLONG ull;
904     ULONG ul;
905     USHORT us;
906     UCHAR uc;
907     PVOID p;
908     BOOLEAN Ok;
909 #ifdef DEBUG_RPN
910     ULONG ValueStackPointerMax = 0;
911 #endif
912 
913     ASSERT(Stack);
914     ASSERT(TrapFrame);
915     ASSERT(Result);
916 
917     for (index = 0; index < Stack->Sp; index++)
918     {
919         PRPN_OP Op = Stack->Ops + index;
920 
921 #ifdef DEBUG_RPN
922         ValueStackPointerMax = max(ValueStackPointerMax, ValueStackPointer);
923 #endif
924 
925         switch (Op->Type)
926         {
927             case RpnOpNop:
928                 /* No operation */
929                 break;
930 
931             case RpnOpImmediate:
932                 if (ValueStackPointer == RPN_VALUE_STACK_SIZE)
933                 {
934                     CONST_STRCPY(ErrMsg, "Value stack overflow");
935 
936                     if (ErrOffset)
937                         *ErrOffset = -1;
938 
939                     return FALSE;
940                 }
941 
942                 ValueStack[ValueStackPointer++] = Op->Data.Immediate;
943                 break;
944 
945             case RpnOpRegister:
946                 if (ValueStackPointer == RPN_VALUE_STACK_SIZE)
947                 {
948                     CONST_STRCPY(ErrMsg, "Value stack overflow");
949 
950                     if (ErrOffset)
951                         *ErrOffset = -1;
952 
953                     return FALSE;
954                 }
955 
956                 ul = Op->Data.Register;
957                 p = (PVOID)((ULONG_PTR)TrapFrame + RegisterToTrapFrame[ul].Offset);
958 
959                 switch (RegisterToTrapFrame[ul].Size)
960                 {
961                     case 1: ull = (ULONGLONG)(*(PUCHAR)p); break;
962                     case 2: ull = (ULONGLONG)(*(PUSHORT)p); break;
963                     case 4: ull = (ULONGLONG)(*(PULONG)p); break;
964                     case 8: ull = (ULONGLONG)(*(PULONGLONG)p); break;
965                     default: ASSERT(0); return FALSE; break;
966                 }
967 
968                 ValueStack[ValueStackPointer++] = ull;
969                 break;
970 
971             case RpnOpDereference:
972                 if (ValueStackPointer < 1)
973                 {
974                     CONST_STRCPY(ErrMsg, "Value stack underflow");
975 
976                     if (ErrOffset)
977                         *ErrOffset = -1;
978 
979                     return FALSE;
980                 }
981 
982                 /* FIXME: Print a warning when address is out of range */
983                 p = (PVOID)(ULONG_PTR)ValueStack[ValueStackPointer - 1];
984                 Ok = FALSE;
985 
986                 switch (Op->Data.DerefMemorySize)
987                 {
988                     case 1:
989                         if (NT_SUCCESS(KdbpSafeReadMemory(&uc, p, sizeof (uc))))
990                         {
991                             Ok = TRUE;
992                             ull = (ULONGLONG)uc;
993                         }
994                         break;
995 
996                     case 2:
997                         if (NT_SUCCESS(KdbpSafeReadMemory(&us, p, sizeof (us))))
998                         {
999                             Ok = TRUE;
1000                             ull = (ULONGLONG)us;
1001                         }
1002                         break;
1003 
1004                     case 4:
1005                         if (NT_SUCCESS(KdbpSafeReadMemory(&ul, p, sizeof (ul))))
1006                         {
1007                             Ok = TRUE;
1008                             ull = (ULONGLONG)ul;
1009                         }
1010                         break;
1011 
1012                     case 8:
1013                         if (NT_SUCCESS(KdbpSafeReadMemory(&ull, p, sizeof (ull))))
1014                         {
1015                             Ok = TRUE;
1016                         }
1017                         break;
1018 
1019                     default:
1020                         ASSERT(0);
1021                         return FALSE;
1022                         break;
1023                 }
1024 
1025                 if (!Ok)
1026                 {
1027                     _snprintf(ErrMsg, 128, "Couldn't access memory at 0x%p", p);
1028 
1029                     if (ErrOffset)
1030                         *ErrOffset = Op->CharacterOffset;
1031 
1032                     return FALSE;
1033                 }
1034 
1035                 ValueStack[ValueStackPointer - 1] = ull;
1036                 break;
1037 
1038             case RpnOpBinaryOperator:
1039                 if (ValueStackPointer < 2)
1040                 {
1041                     CONST_STRCPY(ErrMsg, "Value stack underflow");
1042 
1043                     if (ErrOffset)
1044                         *ErrOffset = -1;
1045 
1046                     return FALSE;
1047                 }
1048 
1049                 ValueStackPointer--;
1050                 ull = ValueStack[ValueStackPointer];
1051 
1052                 if (ull == 0 && Op->Data.BinaryOperator == RpnBinaryOperatorDiv)
1053                 {
1054                     CONST_STRCPY(ErrMsg, "Division by zero");
1055 
1056                     if (ErrOffset)
1057                         *ErrOffset = Op->CharacterOffset;
1058 
1059                     return FALSE;
1060                 }
1061 
1062                 ull = Op->Data.BinaryOperator(ValueStack[ValueStackPointer - 1], ull);
1063                 ValueStack[ValueStackPointer - 1] = ull;
1064                 break;
1065 
1066             default:
1067                 ASSERT(0);
1068                 return FALSE;
1069         }
1070     }
1071 
1072 #ifdef DEBUG_RPN
1073     DPRINT1("Max value stack pointer: %d\n", ValueStackPointerMax);
1074 #endif
1075 
1076     if (ValueStackPointer != 1)
1077     {
1078         CONST_STRCPY(ErrMsg, "Stack not empty after evaluation");
1079 
1080         if (ErrOffset)
1081             *ErrOffset = -1;
1082 
1083         return FALSE;
1084     }
1085 
1086     *Result = ValueStack[0];
1087     return TRUE;
1088 }
1089 
1090 /*!\brief Evaluates the given expression
1091  *
1092  * \param Expression  Expression to evaluate.
1093  * \param TrapFrame   Register values.
1094  * \param Result      Variable which receives the result on success.
1095  * \param ErrOffset   Variable which receives character offset on parse error (-1 on other errors)
1096  * \param ErrMsg      Buffer which receives an error message on failure (128 bytes)
1097  *
1098  * \retval TRUE   Success.
1099  * \retval FALSE  Failure.
1100  */
1101 BOOLEAN
1102 KdbpRpnEvaluateExpression(
1103     IN  PCHAR Expression,
1104     IN  PKDB_KTRAP_FRAME TrapFrame,
1105     OUT PULONGLONG Result,
1106     OUT PLONG ErrOffset  OPTIONAL,
1107     OUT PCHAR ErrMsg  OPTIONAL)
1108 {
1109     PRPN_STACK Stack = (PRPN_STACK)&RpnStack;
1110 
1111     ASSERT(Expression);
1112     ASSERT(TrapFrame);
1113     ASSERT(Result);
1114 
1115     /* Clear the stack and parse the expression */
1116     RpnpClearStack(Stack);
1117     if (!RpnpParseExpression(Stack, Expression, NULL, 0, ErrOffset, ErrMsg))
1118         return FALSE;
1119 
1120 #ifdef DEBUG_RPN
1121     RpnpDumpStack(Stack);
1122 #endif
1123 
1124     /* Evaluate the stack */
1125     if (!RpnpEvaluateStack(Stack, TrapFrame, Result, ErrOffset, ErrMsg))
1126         return FALSE;
1127 
1128     return TRUE;
1129 }
1130 
1131 /*!\brief Parses the given expression and returns a "handle" to it.
1132  *
1133  * \param Expression  Expression to evaluate.
1134  * \param ErrOffset   Variable which receives character offset on parse error (-1 on other errors)
1135  * \param ErrMsg      Buffer which receives an error message on failure (128 bytes)
1136  *
1137  * \returns "Handle" for the expression, NULL on failure.
1138  *
1139  * \sa KdbpRpnEvaluateExpression
1140  */
1141 PVOID
1142 KdbpRpnParseExpression(
1143     IN  PCHAR Expression,
1144     OUT PLONG ErrOffset  OPTIONAL,
1145     OUT PCHAR ErrMsg  OPTIONAL)
1146 {
1147     LONG Size;
1148     PRPN_STACK Stack = (PRPN_STACK)&RpnStack;
1149     PRPN_STACK NewStack;
1150 
1151     ASSERT(Expression);
1152 
1153     /* Clear the stack and parse the expression */
1154     RpnpClearStack(Stack);
1155     if (!RpnpParseExpression(Stack, Expression, NULL, 0, ErrOffset, ErrMsg))
1156         return FALSE;
1157 
1158 #ifdef DEBUG_RPN
1159     RpnpDumpStack(Stack);
1160 #endif
1161 
1162     /* Duplicate the stack and return a pointer/handle to it */
1163     ASSERT(Stack->Sp >= 1);
1164     Size = sizeof (RPN_STACK) + (RTL_FIELD_SIZE(RPN_STACK, Ops[0]) * (Stack->Sp - 1));
1165     NewStack = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_KDBG);
1166 
1167     if (!NewStack)
1168     {
1169         CONST_STRCPY(ErrMsg, "Out of memory");
1170 
1171         if (ErrOffset)
1172             *ErrOffset = -1;
1173 
1174         return NULL;
1175     }
1176 
1177     memcpy(NewStack, Stack, Size);
1178     NewStack->Size = NewStack->Sp;
1179 
1180     return NewStack;
1181 }
1182 
1183 /*!\brief Evaluates the given expression and returns the result.
1184  *
1185  * \param Expression  Expression "handle" returned by KdbpRpnParseExpression.
1186  * \param TrapFrame   Register values.
1187  * \param Result      Variable which receives the result on success.
1188  * \param ErrOffset   Variable which receives character offset on parse error (-1 on other errors)
1189  * \param ErrMsg      Buffer which receives an error message on failure (128 bytes)
1190  *
1191  * \returns "Handle" for the expression, NULL on failure.
1192  *
1193  * \sa KdbpRpnParseExpression
1194  */
1195 BOOLEAN
1196 KdbpRpnEvaluateParsedExpression(
1197     IN  PVOID Expression,
1198     IN  PKDB_KTRAP_FRAME TrapFrame,
1199     OUT PULONGLONG Result,
1200     OUT PLONG ErrOffset  OPTIONAL,
1201     OUT PCHAR ErrMsg  OPTIONAL)
1202 {
1203     PRPN_STACK Stack = (PRPN_STACK)Expression;
1204 
1205     ASSERT(Expression);
1206     ASSERT(TrapFrame);
1207     ASSERT(Result);
1208 
1209     /* Evaluate the stack */
1210     return RpnpEvaluateStack(Stack, TrapFrame, Result, ErrOffset, ErrMsg);
1211 }
1212 
1213