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