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