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 i, i2; 441 ULONG ul; 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 /* FIXME: Need string to ULONGLONG function */ 600 ul = strtoul(p, &pend, 0); 601 if (p != pend) 602 { 603 RpnOp.Type = RpnOpImmediate; 604 RpnOp.CharacterOffset = CharacterOffset; 605 RpnOp.Data.Immediate = (ULONGLONG)ul; 606 CharacterOffset += pend - p; 607 p = pend; 608 } 609 else 610 { 611 CONST_STRCPY(ErrMsg, "Operand expected"); 612 613 if (ErrOffset) 614 *ErrOffset = CharacterOffset; 615 616 return FALSE; 617 } 618 } 619 620 /* Push operand */ 621 if (!RpnpPushStack(Stack, &RpnOp)) 622 { 623 CONST_STRCPY(ErrMsg, "RPN op stack overflow"); 624 625 if (ErrOffset) 626 *ErrOffset = -1; 627 628 return FALSE; 629 } 630 } 631 else if (i == 0) 632 { 633 if (p[0] == '(' || p[0] == '[') /* subexpression */ 634 { 635 if (!RpnpParseExpression(Stack, p + 1, &pend, CharacterOffset + 1, 636 ErrOffset, ErrMsg)) 637 { 638 return FALSE; 639 } 640 else if (pend == p + 1) 641 { 642 CONST_STRCPY(ErrMsg, "Expression expected"); 643 644 if (ErrOffset) 645 *ErrOffset = CharacterOffset + 1; 646 647 return FALSE; 648 } 649 650 if (p[0] == '[') /* dereference */ 651 { 652 ASSERT(MemorySize == 1 || MemorySize == 2 || 653 MemorySize == 4 || MemorySize == 8); 654 655 if (pend[0] != ']') 656 { 657 CONST_STRCPY(ErrMsg, "']' expected"); 658 659 if (ErrOffset) 660 *ErrOffset = CharacterOffset + (pend - p); 661 662 return FALSE; 663 } 664 665 RpnOp.Type = RpnOpDereference; 666 RpnOp.CharacterOffset = CharacterOffset; 667 RpnOp.Data.DerefMemorySize = MemorySize; 668 669 if (!RpnpPushStack(Stack, &RpnOp)) 670 { 671 CONST_STRCPY(ErrMsg, "RPN op stack overflow"); 672 673 if (ErrOffset) 674 *ErrOffset = -1; 675 676 return FALSE; 677 } 678 } 679 else /* p[0] == '(' */ 680 { 681 if (pend[0] != ')') 682 { 683 CONST_STRCPY(ErrMsg, "')' expected"); 684 685 if (ErrOffset) 686 *ErrOffset = CharacterOffset + (pend - p); 687 688 return FALSE; 689 } 690 } 691 692 /* Push a "nop" to prevent popping of the + operator (which would 693 * result in (10+10)/2 beeing evaluated as 15) 694 */ 695 RpnOp.Type = RpnOpNop; 696 if (!RpnpPushStack(Stack, &RpnOp)) 697 { 698 CONST_STRCPY(ErrMsg, "RPN op stack overflow"); 699 700 if (ErrOffset) 701 *ErrOffset = -1; 702 703 return FALSE; 704 } 705 706 /* Skip closing brace/bracket */ 707 pend++; 708 709 CharacterOffset += pend - p; 710 p = pend; 711 } 712 else if (First && p[0] == '-') /* Allow expressions like "- eax" */ 713 { 714 RpnOp.Type = RpnOpImmediate; 715 RpnOp.CharacterOffset = CharacterOffset; 716 RpnOp.Data.Immediate = 0; 717 718 if (!RpnpPushStack(Stack, &RpnOp)) 719 { 720 CONST_STRCPY(ErrMsg, "RPN op stack overflow"); 721 722 if (ErrOffset) 723 *ErrOffset = -1; 724 725 return FALSE; 726 } 727 } 728 else 729 { 730 CONST_STRCPY(ErrMsg, "Operand expected"); 731 732 if (ErrOffset) 733 *ErrOffset = CharacterOffset; 734 735 return FALSE; 736 } 737 } 738 else 739 { 740 CONST_STRCPY(ErrMsg, "strcspn() failed"); 741 742 if (ErrOffset) 743 *ErrOffset = -1; 744 745 return FALSE; 746 } 747 748 if (!First) 749 { 750 /* Push operator */ 751 RpnOp.CharacterOffset = OperatorOffset; 752 RpnOp.Type = RpnOpBinaryOperator; 753 IsComparativeOp = FALSE; 754 755 switch (*Operator) 756 { 757 case '+': 758 RpnOp.Data.BinaryOperator = RpnBinaryOperatorAdd; 759 break; 760 761 case '-': 762 RpnOp.Data.BinaryOperator = RpnBinaryOperatorSub; 763 break; 764 765 case '*': 766 RpnOp.Data.BinaryOperator = RpnBinaryOperatorMul; 767 break; 768 769 case '/': 770 RpnOp.Data.BinaryOperator = RpnBinaryOperatorDiv; 771 break; 772 773 case '%': 774 RpnOp.Data.BinaryOperator = RpnBinaryOperatorMod; 775 break; 776 777 case '=': 778 ASSERT(Operator[1] == '='); 779 IsComparativeOp = TRUE; 780 RpnOp.Data.BinaryOperator = RpnBinaryOperatorEquals; 781 break; 782 783 case '!': 784 ASSERT(Operator[1] == '='); 785 IsComparativeOp = TRUE; 786 RpnOp.Data.BinaryOperator = RpnBinaryOperatorNotEquals; 787 break; 788 789 case '<': 790 IsComparativeOp = TRUE; 791 792 if (Operator[1] == '=') 793 RpnOp.Data.BinaryOperator = RpnBinaryOperatorLessThanOrEquals; 794 else 795 RpnOp.Data.BinaryOperator = RpnBinaryOperatorLessThan; 796 797 break; 798 799 case '>': 800 IsComparativeOp = TRUE; 801 802 if (Operator[1] == '=') 803 RpnOp.Data.BinaryOperator = RpnBinaryOperatorGreaterThanOrEquals; 804 else 805 RpnOp.Data.BinaryOperator = RpnBinaryOperatorGreaterThan; 806 807 break; 808 809 default: 810 ASSERT(0); 811 break; 812 } 813 814 if (IsComparativeOp) 815 { 816 if (ComparativeOpFilled && !RpnpPushStack(Stack, &ComparativeOp)) 817 { 818 CONST_STRCPY(ErrMsg, "RPN op stack overflow"); 819 820 if (ErrOffset) 821 *ErrOffset = -1; 822 823 return FALSE; 824 } 825 826 memcpy(&ComparativeOp, &RpnOp, sizeof(RPN_OP)); 827 ComparativeOpFilled = TRUE; 828 } 829 else if (!RpnpPushStack(Stack, &RpnOp)) 830 { 831 CONST_STRCPY(ErrMsg, "RPN op stack overflow"); 832 833 if (ErrOffset) 834 *ErrOffset = -1; 835 836 return FALSE; 837 } 838 839 /* Push popped operator */ 840 if (HavePoppedOperator) 841 { 842 if (!RpnpPushStack(Stack, &PoppedOperator)) 843 { 844 CONST_STRCPY(ErrMsg, "RPN op stack overflow"); 845 846 if (ErrOffset) 847 *ErrOffset = -1; 848 849 return FALSE; 850 } 851 } 852 } 853 854 First = FALSE; 855 } 856 857 //end_of_expression: 858 859 if (ComparativeOpFilled && !RpnpPushStack(Stack, &ComparativeOp)) 860 { 861 CONST_STRCPY(ErrMsg, "RPN op stack overflow"); 862 863 if (ErrOffset) 864 *ErrOffset = -1; 865 866 return FALSE; 867 } 868 869 /* Skip whitespace */ 870 while (isspace(*p)) 871 { 872 p++; 873 CharacterOffset++; 874 } 875 876 if (End) 877 *End = p; 878 879 return TRUE; 880 } 881 882 /*!\brief Evaluates the RPN op stack and returns the result. 883 * 884 * \param Stack Pointer to a RPN_STACK structure. 885 * \param TrapFrame Register values. 886 * \param Result Pointer to an ULONG to store the result into. 887 * \param ErrOffset On failure this is set to the character offset at which the error occoured. 888 * \param ErrMsg Buffer which receives an error message on failure (128 bytes) 889 * 890 * \retval TRUE Success. 891 * \retval FALSE Failure. 892 */ 893 static BOOLEAN 894 RpnpEvaluateStack( 895 IN PRPN_STACK Stack, 896 IN PKDB_KTRAP_FRAME TrapFrame, 897 OUT PULONGLONG Result, 898 OUT PLONG ErrOffset OPTIONAL, 899 OUT PCHAR ErrMsg OPTIONAL) 900 { 901 ULONGLONG ValueStack[RPN_VALUE_STACK_SIZE]; 902 ULONG ValueStackPointer = 0; 903 ULONG index; 904 ULONGLONG ull; 905 ULONG ul; 906 USHORT us; 907 UCHAR uc; 908 PVOID p; 909 BOOLEAN Ok; 910 #ifdef DEBUG_RPN 911 ULONG ValueStackPointerMax = 0; 912 #endif 913 914 ASSERT(Stack); 915 ASSERT(TrapFrame); 916 ASSERT(Result); 917 918 for (index = 0; index < Stack->Sp; index++) 919 { 920 PRPN_OP Op = Stack->Ops + index; 921 922 #ifdef DEBUG_RPN 923 ValueStackPointerMax = max(ValueStackPointerMax, ValueStackPointer); 924 #endif 925 926 switch (Op->Type) 927 { 928 case RpnOpNop: 929 /* No operation */ 930 break; 931 932 case RpnOpImmediate: 933 if (ValueStackPointer == RPN_VALUE_STACK_SIZE) 934 { 935 CONST_STRCPY(ErrMsg, "Value stack overflow"); 936 937 if (ErrOffset) 938 *ErrOffset = -1; 939 940 return FALSE; 941 } 942 943 ValueStack[ValueStackPointer++] = Op->Data.Immediate; 944 break; 945 946 case RpnOpRegister: 947 if (ValueStackPointer == RPN_VALUE_STACK_SIZE) 948 { 949 CONST_STRCPY(ErrMsg, "Value stack overflow"); 950 951 if (ErrOffset) 952 *ErrOffset = -1; 953 954 return FALSE; 955 } 956 957 ul = Op->Data.Register; 958 p = (PVOID)((ULONG_PTR)TrapFrame + RegisterToTrapFrame[ul].Offset); 959 960 switch (RegisterToTrapFrame[ul].Size) 961 { 962 case 1: ull = (ULONGLONG)(*(PUCHAR)p); break; 963 case 2: ull = (ULONGLONG)(*(PUSHORT)p); break; 964 case 4: ull = (ULONGLONG)(*(PULONG)p); break; 965 case 8: ull = (ULONGLONG)(*(PULONGLONG)p); break; 966 default: ASSERT(0); return FALSE; break; 967 } 968 969 ValueStack[ValueStackPointer++] = ull; 970 break; 971 972 case RpnOpDereference: 973 if (ValueStackPointer < 1) 974 { 975 CONST_STRCPY(ErrMsg, "Value stack underflow"); 976 977 if (ErrOffset) 978 *ErrOffset = -1; 979 980 return FALSE; 981 } 982 983 /* FIXME: Print a warning when address is out of range */ 984 p = (PVOID)(ULONG_PTR)ValueStack[ValueStackPointer - 1]; 985 Ok = FALSE; 986 987 switch (Op->Data.DerefMemorySize) 988 { 989 case 1: 990 if (NT_SUCCESS(KdbpSafeReadMemory(&uc, p, sizeof (uc)))) 991 { 992 Ok = TRUE; 993 ull = (ULONGLONG)uc; 994 } 995 break; 996 997 case 2: 998 if (NT_SUCCESS(KdbpSafeReadMemory(&us, p, sizeof (us)))) 999 { 1000 Ok = TRUE; 1001 ull = (ULONGLONG)us; 1002 } 1003 break; 1004 1005 case 4: 1006 if (NT_SUCCESS(KdbpSafeReadMemory(&ul, p, sizeof (ul)))) 1007 { 1008 Ok = TRUE; 1009 ull = (ULONGLONG)ul; 1010 } 1011 break; 1012 1013 case 8: 1014 if (NT_SUCCESS(KdbpSafeReadMemory(&ull, p, sizeof (ull)))) 1015 { 1016 Ok = TRUE; 1017 } 1018 break; 1019 1020 default: 1021 ASSERT(0); 1022 return FALSE; 1023 break; 1024 } 1025 1026 if (!Ok) 1027 { 1028 _snprintf(ErrMsg, 128, "Couldn't access memory at 0x%p", p); 1029 1030 if (ErrOffset) 1031 *ErrOffset = Op->CharacterOffset; 1032 1033 return FALSE; 1034 } 1035 1036 ValueStack[ValueStackPointer - 1] = ull; 1037 break; 1038 1039 case RpnOpBinaryOperator: 1040 if (ValueStackPointer < 2) 1041 { 1042 CONST_STRCPY(ErrMsg, "Value stack underflow"); 1043 1044 if (ErrOffset) 1045 *ErrOffset = -1; 1046 1047 return FALSE; 1048 } 1049 1050 ValueStackPointer--; 1051 ull = ValueStack[ValueStackPointer]; 1052 1053 if (ull == 0 && Op->Data.BinaryOperator == RpnBinaryOperatorDiv) 1054 { 1055 CONST_STRCPY(ErrMsg, "Division by zero"); 1056 1057 if (ErrOffset) 1058 *ErrOffset = Op->CharacterOffset; 1059 1060 return FALSE; 1061 } 1062 1063 ull = Op->Data.BinaryOperator(ValueStack[ValueStackPointer - 1], ull); 1064 ValueStack[ValueStackPointer - 1] = ull; 1065 break; 1066 1067 default: 1068 ASSERT(0); 1069 return FALSE; 1070 } 1071 } 1072 1073 #ifdef DEBUG_RPN 1074 DPRINT1("Max value stack pointer: %d\n", ValueStackPointerMax); 1075 #endif 1076 1077 if (ValueStackPointer != 1) 1078 { 1079 CONST_STRCPY(ErrMsg, "Stack not empty after evaluation"); 1080 1081 if (ErrOffset) 1082 *ErrOffset = -1; 1083 1084 return FALSE; 1085 } 1086 1087 *Result = ValueStack[0]; 1088 return TRUE; 1089 } 1090 1091 /*!\brief Evaluates the given expression 1092 * 1093 * \param Expression Expression to evaluate. 1094 * \param TrapFrame Register values. 1095 * \param Result Variable which receives the result on success. 1096 * \param ErrOffset Variable which receives character offset on parse error (-1 on other errors) 1097 * \param ErrMsg Buffer which receives an error message on failure (128 bytes) 1098 * 1099 * \retval TRUE Success. 1100 * \retval FALSE Failure. 1101 */ 1102 BOOLEAN 1103 KdbpRpnEvaluateExpression( 1104 IN PCHAR Expression, 1105 IN PKDB_KTRAP_FRAME TrapFrame, 1106 OUT PULONGLONG Result, 1107 OUT PLONG ErrOffset OPTIONAL, 1108 OUT PCHAR ErrMsg OPTIONAL) 1109 { 1110 PRPN_STACK Stack = (PRPN_STACK)&RpnStack; 1111 1112 ASSERT(Expression); 1113 ASSERT(TrapFrame); 1114 ASSERT(Result); 1115 1116 /* Clear the stack and parse the expression */ 1117 RpnpClearStack(Stack); 1118 if (!RpnpParseExpression(Stack, Expression, NULL, 0, ErrOffset, ErrMsg)) 1119 return FALSE; 1120 1121 #ifdef DEBUG_RPN 1122 RpnpDumpStack(Stack); 1123 #endif 1124 1125 /* Evaluate the stack */ 1126 if (!RpnpEvaluateStack(Stack, TrapFrame, Result, ErrOffset, ErrMsg)) 1127 return FALSE; 1128 1129 return TRUE; 1130 } 1131 1132 /*!\brief Parses the given expression and returns a "handle" to it. 1133 * 1134 * \param Expression Expression to evaluate. 1135 * \param ErrOffset Variable which receives character offset on parse error (-1 on other errors) 1136 * \param ErrMsg Buffer which receives an error message on failure (128 bytes) 1137 * 1138 * \returns "Handle" for the expression, NULL on failure. 1139 * 1140 * \sa KdbpRpnEvaluateExpression 1141 */ 1142 PVOID 1143 KdbpRpnParseExpression( 1144 IN PCHAR Expression, 1145 OUT PLONG ErrOffset OPTIONAL, 1146 OUT PCHAR ErrMsg OPTIONAL) 1147 { 1148 LONG Size; 1149 PRPN_STACK Stack = (PRPN_STACK)&RpnStack; 1150 PRPN_STACK NewStack; 1151 1152 ASSERT(Expression); 1153 1154 /* Clear the stack and parse the expression */ 1155 RpnpClearStack(Stack); 1156 if (!RpnpParseExpression(Stack, Expression, NULL, 0, ErrOffset, ErrMsg)) 1157 return FALSE; 1158 1159 #ifdef DEBUG_RPN 1160 RpnpDumpStack(Stack); 1161 #endif 1162 1163 /* Duplicate the stack and return a pointer/handle to it */ 1164 ASSERT(Stack->Sp >= 1); 1165 Size = sizeof (RPN_STACK) + (RTL_FIELD_SIZE(RPN_STACK, Ops[0]) * (Stack->Sp - 1)); 1166 NewStack = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_KDBG); 1167 1168 if (!NewStack) 1169 { 1170 CONST_STRCPY(ErrMsg, "Out of memory"); 1171 1172 if (ErrOffset) 1173 *ErrOffset = -1; 1174 1175 return NULL; 1176 } 1177 1178 memcpy(NewStack, Stack, Size); 1179 NewStack->Size = NewStack->Sp; 1180 1181 return NewStack; 1182 } 1183 1184 /*!\brief Evaluates the given expression and returns the result. 1185 * 1186 * \param Expression Expression "handle" returned by KdbpRpnParseExpression. 1187 * \param TrapFrame Register values. 1188 * \param Result Variable which receives the result on success. 1189 * \param ErrOffset Variable which receives character offset on parse error (-1 on other errors) 1190 * \param ErrMsg Buffer which receives an error message on failure (128 bytes) 1191 * 1192 * \returns "Handle" for the expression, NULL on failure. 1193 * 1194 * \sa KdbpRpnParseExpression 1195 */ 1196 BOOLEAN 1197 KdbpRpnEvaluateParsedExpression( 1198 IN PVOID Expression, 1199 IN PKDB_KTRAP_FRAME TrapFrame, 1200 OUT PULONGLONG Result, 1201 OUT PLONG ErrOffset OPTIONAL, 1202 OUT PCHAR ErrMsg OPTIONAL) 1203 { 1204 PRPN_STACK Stack = (PRPN_STACK)Expression; 1205 1206 ASSERT(Expression); 1207 ASSERT(TrapFrame); 1208 ASSERT(Result); 1209 1210 /* Evaluate the stack */ 1211 return RpnpEvaluateStack(Stack, TrapFrame, Result, ErrOffset, ErrMsg); 1212 } 1213 1214