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