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 160 RpnBinaryOperatorAdd( 161 ULONGLONG a, 162 ULONGLONG b) 163 { 164 return a + b; 165 } 166 167 ULONGLONG 168 RpnBinaryOperatorSub( 169 ULONGLONG a, 170 ULONGLONG b) 171 { 172 return a - b; 173 } 174 175 ULONGLONG 176 RpnBinaryOperatorMul( 177 ULONGLONG a, 178 ULONGLONG b) 179 { 180 return a * b; 181 } 182 183 ULONGLONG 184 RpnBinaryOperatorDiv( 185 ULONGLONG a, 186 ULONGLONG b) 187 { 188 return a / b; 189 } 190 191 ULONGLONG 192 RpnBinaryOperatorMod( 193 ULONGLONG a, 194 ULONGLONG b) 195 { 196 return a % b; 197 } 198 199 ULONGLONG 200 RpnBinaryOperatorEquals( 201 ULONGLONG a, 202 ULONGLONG b) 203 { 204 return (a == b); 205 } 206 207 ULONGLONG 208 RpnBinaryOperatorNotEquals( 209 ULONGLONG a, 210 ULONGLONG b) 211 { 212 return (a != b); 213 } 214 215 ULONGLONG 216 RpnBinaryOperatorLessThan( 217 ULONGLONG a, 218 ULONGLONG b) 219 { 220 return (a < b); 221 } 222 223 ULONGLONG 224 RpnBinaryOperatorLessThanOrEquals( 225 ULONGLONG a, 226 ULONGLONG b) 227 { 228 return (a <= b); 229 } 230 231 ULONGLONG 232 RpnBinaryOperatorGreaterThan( 233 ULONGLONG a, 234 ULONGLONG b) 235 { 236 return (a > b); 237 } 238 239 ULONGLONG 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 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 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 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 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 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 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 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 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 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 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