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