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