1 /* 2 * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de 3 * Copyright 2006, Stephan Aßmus, superstippi@gmx.de 4 * Distributed under the terms of the MIT License. 5 */ 6 7 #include <debug.h> 8 9 #include <ctype.h> 10 #include <setjmp.h> 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <string.h> 14 15 #include <KernelExport.h> 16 17 #include <debug_heap.h> 18 19 #include "debug_commands.h" 20 #include "debug_variables.h" 21 22 23 /* 24 Grammar: 25 26 commandLine := commandPipe | ( "(" expression ")" ) 27 expression := term | assignment 28 assignment := lhs ( "=" | "+=" | "-=" | "*=" | "/=" | "%=" ) 29 expression 30 lhs := variable | dereference 31 term := sum 32 sum := product ( ( "+" | "-" ) product )* 33 product := unary ( ( "*" | "/" | "%" ) unary )* 34 unary := atom | ( "-" unary ) | dereference 35 dereference := "*" [ "{" expression "}" ] unary 36 atom := variable | ( "(" expression ")" ) | ( "[" command "]" ) 37 variable := identifier 38 identifier := ( "$" | "_" | "a" - "z" | "A" - "Z" ) 39 ( "_" | "a" - "z" | "A" - "Z" | "0" - "9" )* 40 commandPipe := command ( "|" command )* 41 command := identifier argument* 42 argument := ( "(" expression ")" ) | ( "[" commandLine "]" ) 43 | unquotedString | quotedString 44 */ 45 46 47 static const int kMaxTokenLength = 128; 48 static const int kJumpBufferCount = 10; 49 50 static const int kMaxArgumentCount = 64; 51 52 static jmp_buf sJumpBuffers[kJumpBufferCount]; 53 static int sNextJumpBufferIndex = 0; 54 55 static char sExceptionMessage[128]; 56 static int sExceptionPosition; 57 58 static char sTempBuffer[128]; 59 // for composing debug output etc. 60 61 enum { 62 TOKEN_ASSIGN_FLAG = 0x100, 63 TOKEN_FLAGS = TOKEN_ASSIGN_FLAG, 64 65 TOKEN_IDENTIFIER = 'a', 66 67 TOKEN_CONSTANT = '0', 68 69 TOKEN_PLUS = '+', 70 TOKEN_MINUS = '-', 71 72 TOKEN_STAR = '*', 73 TOKEN_SLASH = '/', 74 TOKEN_MODULO = '%', 75 76 TOKEN_ASSIGN = '=' | TOKEN_ASSIGN_FLAG, 77 TOKEN_PLUS_ASSIGN = TOKEN_PLUS | TOKEN_ASSIGN_FLAG, 78 TOKEN_MINUS_ASSIGN = TOKEN_MINUS | TOKEN_ASSIGN_FLAG, 79 TOKEN_STAR_ASSIGN = TOKEN_STAR | TOKEN_ASSIGN_FLAG, 80 TOKEN_SLASH_ASSIGN = TOKEN_SLASH | TOKEN_ASSIGN_FLAG, 81 TOKEN_MODULO_ASSIGN = TOKEN_MODULO | TOKEN_ASSIGN_FLAG, 82 83 TOKEN_OPENING_PARENTHESIS = '(', 84 TOKEN_CLOSING_PARENTHESIS = ')', 85 TOKEN_OPENING_BRACKET = '[', 86 TOKEN_CLOSING_BRACKET = ']', 87 TOKEN_OPENING_BRACE = '{', 88 TOKEN_CLOSING_BRACE = '}', 89 90 TOKEN_PIPE = '|', 91 92 TOKEN_STRING = '"', 93 TOKEN_UNKNOWN = '?', 94 TOKEN_NONE = ' ', 95 TOKEN_END_OF_LINE = '\n', 96 }; 97 98 struct Token { 99 char string[kMaxTokenLength]; 100 uint64 value; 101 int32 type; 102 int32 position; 103 104 void SetTo(const char* string, int32 length, int32 position, int32 type) 105 { 106 length = min_c((size_t)length, (sizeof(this->string) - 1)); 107 strlcpy(this->string, string, length + 1); 108 this->type = type; 109 this->value = 0; 110 this->position = position; 111 } 112 113 void Unset() 114 { 115 string[0] = '\0'; 116 value = 0; 117 type = TOKEN_NONE; 118 position = 0; 119 } 120 }; 121 122 123 // #pragma mark - exceptions 124 125 126 static void 127 parse_exception(const char* message, int32 position) 128 { 129 if (sNextJumpBufferIndex == 0) { 130 kprintf_unfiltered("parse_exception(): No jump buffer!\n"); 131 kprintf_unfiltered("exception: \"%s\", position: %lu\n", message, 132 position); 133 return; 134 } 135 136 strlcpy(sExceptionMessage, message, sizeof(sExceptionMessage)); 137 sExceptionPosition = position; 138 139 longjmp(sJumpBuffers[sNextJumpBufferIndex - 1], 1); 140 } 141 142 143 static void* 144 checked_malloc(size_t size) 145 { 146 void* address = debug_malloc(size); 147 if (address == NULL) { 148 parse_exception("out of memory for command execution", -1); 149 return NULL; 150 } 151 152 return address; 153 } 154 155 156 // #pragma mark - Tokenizer 157 158 159 class Tokenizer { 160 public: 161 Tokenizer(const char* string) 162 : fCommandMode(false) 163 { 164 SetTo(string); 165 } 166 167 void SetTo(const char* string) 168 { 169 fString = fCurrentChar = string; 170 fCurrentToken.Unset(); 171 fReuseToken = false; 172 } 173 174 void SetPosition(int32 position) 175 { 176 fCurrentChar = fString + position; 177 fCurrentToken.Unset(); 178 fReuseToken = false; 179 } 180 181 void SetCommandMode(bool commandMode) 182 { 183 fCommandMode = commandMode; 184 } 185 186 const char* String() const 187 { 188 return fString; 189 } 190 191 const Token& NextToken() 192 { 193 if (fCurrentToken.type == TOKEN_END_OF_LINE) 194 return fCurrentToken; 195 196 if (fReuseToken) { 197 fReuseToken = false; 198 return fCurrentToken; 199 } 200 201 while (*fCurrentChar != 0 && isspace(*fCurrentChar)) 202 fCurrentChar++; 203 204 if (*fCurrentChar == 0) { 205 fCurrentToken.SetTo("", 0, _CurrentPos(), TOKEN_END_OF_LINE); 206 return fCurrentToken; 207 } 208 209 return (fCommandMode ? _NextTokenCommand() : _NextTokenExpression()); 210 } 211 212 const Token& CurrentToken() const 213 { 214 return fCurrentToken; 215 } 216 217 void RewindToken() 218 { 219 fReuseToken = true; 220 } 221 222 private: 223 const Token& _NextTokenExpression() 224 { 225 if (isdigit(*fCurrentChar)) { 226 // number 227 const char* begin = fCurrentChar++; 228 229 if (*fCurrentChar == 'x') { 230 // hex number 231 fCurrentChar++; 232 while (*fCurrentChar != 0 233 && (isdigit(*fCurrentChar) 234 || strchr("abcdefABCDEF", *fCurrentChar))) { 235 fCurrentChar++; 236 } 237 238 if (fCurrentChar - begin == 2) 239 parse_exception("invalid hex number", begin - fString); 240 241 } else { 242 // decimal number 243 while (*fCurrentChar != 0 && isdigit(*fCurrentChar)) 244 fCurrentChar++; 245 } 246 247 int32 length = fCurrentChar - begin; 248 fCurrentToken.SetTo(begin, length, _CurrentPos() - length, 249 TOKEN_CONSTANT); 250 fCurrentToken.value = strtoull(fCurrentToken.string, NULL, 0); 251 252 } else if (isalpha(*fCurrentChar) || *fCurrentChar == '_' 253 || *fCurrentChar == '$') { 254 // identifier 255 const char* begin = fCurrentChar; 256 fCurrentChar++; 257 while (*fCurrentChar != 0 258 && (isalpha(*fCurrentChar) || *fCurrentChar == '_' 259 || isdigit(*fCurrentChar))) { 260 fCurrentChar++; 261 } 262 263 int32 length = fCurrentChar - begin; 264 fCurrentToken.SetTo(begin, length, _CurrentPos() - length, 265 TOKEN_IDENTIFIER); 266 267 } else { 268 const char* begin = fCurrentChar; 269 char c = *fCurrentChar; 270 fCurrentChar++; 271 int32 flags = 0; 272 273 switch (c) { 274 case '=': 275 fCurrentChar--; 276 case '+': 277 case '-': 278 case '*': 279 case '/': 280 case '%': 281 if (*fCurrentChar == '=') { 282 fCurrentChar++; 283 flags = TOKEN_ASSIGN_FLAG; 284 } 285 286 case '(': 287 case ')': 288 case '[': 289 case ']': 290 case '{': 291 case '}': 292 { 293 int32 length = fCurrentChar - begin; 294 fCurrentToken.SetTo(begin, length, _CurrentPos() - length, 295 c | flags); 296 break; 297 } 298 299 case '"': 300 { 301 fCurrentChar--; 302 _QuotedString(); 303 break; 304 } 305 306 default: 307 { 308 fCurrentChar--; 309 _UnquotedString(); 310 break; 311 } 312 } 313 } 314 315 return fCurrentToken; 316 } 317 318 const Token& _NextTokenCommand() 319 { 320 switch (*fCurrentChar) { 321 case '(': 322 case ')': 323 case '[': 324 case ']': 325 case '|': 326 fCurrentToken.SetTo(fCurrentChar, 1, _CurrentPos(), 327 *fCurrentChar); 328 fCurrentChar++; 329 return fCurrentToken; 330 case '"': 331 return _QuotedString(); 332 333 default: 334 return _UnquotedString(); 335 } 336 } 337 338 const Token& _QuotedString() 339 { 340 const char* begin = fCurrentChar++; 341 int32 length = 0; 342 343 while (*fCurrentChar != '\0' && *fCurrentChar != '"') { 344 char c = *fCurrentChar; 345 fCurrentChar++; 346 347 if (c == '\\') { 348 // an escaped char 349 c = *fCurrentChar; 350 fCurrentChar++; 351 352 if (c == '\0') 353 break; 354 } 355 356 if ((size_t)length 357 >= sizeof(fCurrentToken.string) - 1) { 358 parse_exception("quoted string too long", begin - fString); 359 } 360 361 fCurrentToken.string[length++] = c; 362 } 363 364 if (*fCurrentChar == '\0') { 365 parse_exception("unexpected end of line while " 366 "parsing quoted string", begin - fString); 367 } 368 369 fCurrentChar++; 370 371 fCurrentToken.string[length] = '\0'; 372 fCurrentToken.value = 0; 373 fCurrentToken.type = TOKEN_STRING; 374 fCurrentToken.position = begin - fString; 375 376 return fCurrentToken; 377 } 378 379 const Token& _UnquotedString() 380 { 381 const char* begin = fCurrentChar; 382 383 while (*fCurrentChar != 0 && !_IsUnquotedDelimitingChar(*fCurrentChar)) 384 fCurrentChar++; 385 386 int32 length = fCurrentChar - begin; 387 fCurrentToken.SetTo(begin, length, _CurrentPos() - length, 388 TOKEN_UNKNOWN); 389 390 return fCurrentToken; 391 } 392 393 bool _IsUnquotedDelimitingChar(char c) 394 { 395 if (isspace(c)) 396 return true; 397 398 switch (c) { 399 case '(': 400 case ')': 401 case '[': 402 case ']': 403 case '"': 404 return true; 405 406 case '{': 407 case '}': 408 case '=': 409 case '+': 410 case '-': 411 case '*': 412 case '/': 413 case '%': 414 return !fCommandMode; 415 416 default: 417 return false; 418 } 419 } 420 421 int32 _CurrentPos() const 422 { 423 return fCurrentChar - fString; 424 } 425 426 private: 427 const char* fString; 428 const char* fCurrentChar; 429 Token fCurrentToken; 430 bool fReuseToken; 431 bool fCommandMode; 432 }; 433 434 435 // #pragma mark - ExpressionParser 436 437 438 class ExpressionParser { 439 public: 440 ExpressionParser(); 441 ~ExpressionParser(); 442 443 uint64 EvaluateExpression( 444 const char* expressionString); 445 uint64 EvaluateCommand( 446 const char* expressionString, 447 int& returnCode); 448 status_t ParseNextCommandArgument( 449 const char** expressionString, char* buffer, 450 size_t bufferSize); 451 452 private: 453 uint64 _ParseExpression(bool expectAssignment = false); 454 uint64 _ParseCommandPipe(int& returnCode); 455 void _ParseCommand( 456 debugger_command_pipe_segment& segment); 457 bool _ParseArgument(int& argc, char** argv); 458 void _GetUnparsedArgument(int& argc, char** argv); 459 void _AddArgument(int& argc, char** argv, 460 const char* argument, int32 length = -1); 461 uint64 _ParseSum(bool useValue, uint64 value); 462 uint64 _ParseProduct(); 463 uint64 _ParsePower(); 464 uint64 _ParseUnary(); 465 uint64 _ParseDereference(void** _address, 466 uint32* _size); 467 uint64 _ParseAtom(); 468 469 const Token& _EatToken(int32 type); 470 471 Tokenizer fTokenizer; 472 }; 473 474 475 ExpressionParser::ExpressionParser() 476 : fTokenizer("") 477 { 478 } 479 480 481 ExpressionParser::~ExpressionParser() 482 { 483 } 484 485 486 uint64 487 ExpressionParser::EvaluateExpression(const char* expressionString) 488 { 489 fTokenizer.SetTo(expressionString); 490 491 uint64 value = _ParseExpression(); 492 const Token& token = fTokenizer.NextToken(); 493 if (token.type != TOKEN_END_OF_LINE) 494 parse_exception("parse error", token.position); 495 496 return value; 497 } 498 499 500 uint64 501 ExpressionParser::EvaluateCommand(const char* expressionString, int& returnCode) 502 { 503 fTokenizer.SetTo(expressionString); 504 505 // Allowed are command or assignment. A command always starts with an 506 // identifier, an assignment either with an identifier (variable name) or 507 // a dereferenced address. 508 const Token& token = fTokenizer.NextToken(); 509 uint64 value = 0; 510 511 if (token.type == TOKEN_IDENTIFIER) { 512 fTokenizer.NextToken(); 513 if (token.type & TOKEN_ASSIGN_FLAG) { 514 // an assignment 515 fTokenizer.SetTo(expressionString); 516 value = _ParseExpression(true); 517 returnCode = 0; 518 } else { 519 // no assignment, so let's assume it's a command 520 fTokenizer.SetTo(expressionString); 521 fTokenizer.SetCommandMode(true); 522 value = _ParseCommandPipe(returnCode); 523 } 524 } else if (token.type == TOKEN_STAR) { 525 // dereferenced address -- assignment 526 fTokenizer.SetTo(expressionString); 527 value = _ParseExpression(true); 528 returnCode = 0; 529 } else 530 parse_exception("expected command or assignment", 0); 531 532 if (token.type != TOKEN_END_OF_LINE) 533 parse_exception("parse error", token.position); 534 535 return value; 536 } 537 538 539 status_t 540 ExpressionParser::ParseNextCommandArgument(const char** expressionString, 541 char* buffer, size_t bufferSize) 542 { 543 fTokenizer.SetTo(*expressionString); 544 fTokenizer.SetCommandMode(true); 545 546 if (fTokenizer.NextToken().type == TOKEN_END_OF_LINE) 547 return B_ENTRY_NOT_FOUND; 548 549 fTokenizer.RewindToken(); 550 551 char* argv[2]; 552 int argc = 0; 553 if (!_ParseArgument(argc, argv)) 554 return B_BAD_VALUE; 555 556 strlcpy(buffer, argv[0], bufferSize); 557 558 const Token& token = fTokenizer.NextToken(); 559 if (token.type == TOKEN_END_OF_LINE) 560 *expressionString = NULL; 561 else 562 *expressionString += token.position; 563 564 return B_OK; 565 } 566 567 568 uint64 569 ExpressionParser::_ParseExpression(bool expectAssignment) 570 { 571 const Token& token = fTokenizer.NextToken(); 572 int32 position = token.position; 573 if (token.type == TOKEN_IDENTIFIER) { 574 char variable[MAX_DEBUG_VARIABLE_NAME_LEN]; 575 strlcpy(variable, token.string, sizeof(variable)); 576 577 int32 assignmentType = fTokenizer.NextToken().type; 578 if (assignmentType & TOKEN_ASSIGN_FLAG) { 579 // an assignment 580 uint64 rhs = _ParseExpression(); 581 582 // handle the standard assignment separately -- the other kinds 583 // need the variable to be defined 584 if (assignmentType == TOKEN_ASSIGN) { 585 if (!set_debug_variable(variable, rhs)) { 586 snprintf(sTempBuffer, sizeof(sTempBuffer), 587 "failed to set value for variable \"%s\"", 588 variable); 589 parse_exception(sTempBuffer, position); 590 } 591 592 return rhs; 593 } 594 595 // variable must be defined 596 if (!is_debug_variable_defined(variable)) { 597 snprintf(sTempBuffer, sizeof(sTempBuffer), 598 "variable \"%s\" not defined in modifying assignment", 599 variable); 600 parse_exception(sTempBuffer, position); 601 } 602 603 uint64 variableValue = get_debug_variable(variable, 0); 604 605 // check for division by zero for the respective assignment types 606 if ((assignmentType == TOKEN_SLASH_ASSIGN 607 || assignmentType == TOKEN_MODULO_ASSIGN) 608 && rhs == 0) { 609 parse_exception("division by zero", position); 610 } 611 612 // compute the new variable value 613 switch (assignmentType) { 614 case TOKEN_PLUS_ASSIGN: 615 variableValue += rhs; 616 break; 617 case TOKEN_MINUS_ASSIGN: 618 variableValue -= rhs; 619 break; 620 case TOKEN_STAR_ASSIGN: 621 variableValue *= rhs; 622 break; 623 case TOKEN_SLASH_ASSIGN: 624 variableValue /= rhs; 625 break; 626 case TOKEN_MODULO_ASSIGN: 627 variableValue %= rhs; 628 break; 629 default: 630 parse_exception("internal error: unknown assignment token", 631 position); 632 break; 633 } 634 635 set_debug_variable(variable, variableValue); 636 return variableValue; 637 } 638 } else if (token.type == TOKEN_STAR) { 639 void* address; 640 uint32 size; 641 uint64 value = _ParseDereference(&address, &size); 642 643 int32 assignmentType = fTokenizer.NextToken().type; 644 if (assignmentType & TOKEN_ASSIGN_FLAG) { 645 // an assignment 646 uint64 rhs = _ParseExpression(); 647 648 // check for division by zero for the respective assignment types 649 if ((assignmentType == TOKEN_SLASH_ASSIGN 650 || assignmentType == TOKEN_MODULO_ASSIGN) 651 && rhs == 0) { 652 parse_exception("division by zero", position); 653 } 654 655 // compute the new value 656 switch (assignmentType) { 657 case TOKEN_ASSIGN: 658 value = rhs; 659 break; 660 case TOKEN_PLUS_ASSIGN: 661 value += rhs; 662 break; 663 case TOKEN_MINUS_ASSIGN: 664 value -= rhs; 665 break; 666 case TOKEN_STAR_ASSIGN: 667 value *= rhs; 668 break; 669 case TOKEN_SLASH_ASSIGN: 670 value /= rhs; 671 break; 672 case TOKEN_MODULO_ASSIGN: 673 value %= rhs; 674 break; 675 default: 676 parse_exception("internal error: unknown assignment token", 677 position); 678 break; 679 } 680 681 // convert the value for writing to the address 682 uint64 buffer = 0; 683 switch (size) { 684 case 1: 685 *(uint8*)&buffer = value; 686 break; 687 case 2: 688 *(uint16*)&buffer = value; 689 break; 690 case 4: 691 *(uint32*)&buffer = value; 692 break; 693 case 8: 694 value = buffer; 695 break; 696 } 697 698 if (user_memcpy(address, &buffer, size) != B_OK) { 699 snprintf(sTempBuffer, sizeof(sTempBuffer), 700 "failed to write to address %p", address); 701 parse_exception(sTempBuffer, position); 702 } 703 704 return value; 705 } 706 } 707 708 if (expectAssignment) { 709 parse_exception("expected assignment", 710 fTokenizer.CurrentToken().position); 711 } 712 713 // no assignment -- reset to the identifier position and parse a sum 714 fTokenizer.SetPosition(position); 715 return _ParseSum(false, 0); 716 } 717 718 719 uint64 720 ExpressionParser::_ParseCommandPipe(int& returnCode) 721 { 722 debugger_command_pipe* pipe = (debugger_command_pipe*)checked_malloc( 723 sizeof(debugger_command_pipe)); 724 725 pipe->segment_count = 0; 726 pipe->broken = false; 727 728 do { 729 if (pipe->segment_count >= MAX_DEBUGGER_COMMAND_PIPE_LENGTH) 730 parse_exception("Pipe too long", fTokenizer.NextToken().position); 731 732 debugger_command_pipe_segment& segment 733 = pipe->segments[pipe->segment_count]; 734 segment.index = pipe->segment_count++; 735 736 _ParseCommand(segment); 737 738 } while (fTokenizer.NextToken().type == TOKEN_PIPE); 739 740 fTokenizer.RewindToken(); 741 742 // invoke the pipe 743 returnCode = invoke_debugger_command_pipe(pipe); 744 745 debug_free(pipe); 746 747 return get_debug_variable("_", 0); 748 } 749 750 751 void 752 ExpressionParser::_ParseCommand(debugger_command_pipe_segment& segment) 753 { 754 fTokenizer.SetCommandMode(false); 755 const Token& token = _EatToken(TOKEN_IDENTIFIER); 756 fTokenizer.SetCommandMode(true); 757 758 bool ambiguous; 759 debugger_command* command = find_debugger_command(token.string, true, 760 ambiguous); 761 762 if (command == NULL) { 763 if (ambiguous) { 764 snprintf(sTempBuffer, sizeof(sTempBuffer), 765 "Ambiguous command \"%s\". Use tab completion or enter " 766 "\"help %s\" get a list of matching commands.\n", token.string, 767 token.string); 768 } else { 769 snprintf(sTempBuffer, sizeof(sTempBuffer), 770 "Unknown command \"%s\". Enter \"help\" to get a list of " 771 "all supported commands.\n", token.string); 772 } 773 774 parse_exception(sTempBuffer, -1); 775 } 776 777 // allocate temporary buffer for the argument vector 778 char** argv = (char**)checked_malloc(kMaxArgumentCount * sizeof(char*)); 779 int argc = 0; 780 argv[argc++] = (char*)command->name; 781 782 // get the arguments 783 if ((command->flags & B_KDEBUG_DONT_PARSE_ARGUMENTS) != 0) { 784 _GetUnparsedArgument(argc, argv); 785 } else { 786 while (fTokenizer.NextToken().type != TOKEN_END_OF_LINE) { 787 fTokenizer.RewindToken(); 788 if (!_ParseArgument(argc, argv)) 789 break; 790 } 791 } 792 793 if (segment.index > 0) { 794 if (argc >= kMaxArgumentCount) 795 parse_exception("too many arguments for command", 0); 796 else 797 argc++; 798 } 799 800 segment.command = command; 801 segment.argc = argc; 802 segment.argv = argv; 803 segment.invocations = 0; 804 } 805 806 807 bool 808 ExpressionParser::_ParseArgument(int& argc, char** argv) 809 { 810 const Token& token = fTokenizer.NextToken(); 811 switch (token.type) { 812 case TOKEN_OPENING_PARENTHESIS: 813 { 814 // this starts an expression 815 fTokenizer.SetCommandMode(false); 816 uint64 value = _ParseExpression(); 817 fTokenizer.SetCommandMode(true); 818 _EatToken(TOKEN_CLOSING_PARENTHESIS); 819 820 snprintf(sTempBuffer, sizeof(sTempBuffer), "%llu", value); 821 _AddArgument(argc, argv, sTempBuffer); 822 return true; 823 } 824 825 case TOKEN_OPENING_BRACKET: 826 { 827 // this starts a sub command 828 int returnValue; 829 uint64 value = _ParseCommandPipe(returnValue); 830 _EatToken(TOKEN_CLOSING_BRACKET); 831 832 snprintf(sTempBuffer, sizeof(sTempBuffer), "%llu", value); 833 _AddArgument(argc, argv, sTempBuffer); 834 return true; 835 } 836 837 case TOKEN_STRING: 838 case TOKEN_UNKNOWN: 839 _AddArgument(argc, argv, token.string); 840 return true; 841 842 case TOKEN_CLOSING_PARENTHESIS: 843 case TOKEN_CLOSING_BRACKET: 844 case TOKEN_PIPE: 845 // those don't belong to us 846 fTokenizer.RewindToken(); 847 return false; 848 849 default: 850 { 851 snprintf(sTempBuffer, sizeof(sTempBuffer), "unexpected token " 852 "\"%s\"", token.string); 853 parse_exception(sTempBuffer, token.position); 854 return false; 855 } 856 } 857 } 858 859 860 void 861 ExpressionParser::_GetUnparsedArgument(int& argc, char** argv) 862 { 863 int32 startPosition = fTokenizer.NextToken().position; 864 fTokenizer.RewindToken(); 865 866 // match parentheses and brackets, but otherwise skip all tokens 867 int32 parentheses = 0; 868 int32 brackets = 0; 869 bool done = false; 870 while (!done) { 871 const Token& token = fTokenizer.NextToken(); 872 switch (token.type) { 873 case TOKEN_OPENING_PARENTHESIS: 874 parentheses++; 875 break; 876 case TOKEN_OPENING_BRACKET: 877 brackets++; 878 break; 879 case TOKEN_CLOSING_PARENTHESIS: 880 if (parentheses > 0) 881 parentheses--; 882 else 883 done = true; 884 break; 885 case TOKEN_CLOSING_BRACKET: 886 if (brackets > 0) 887 brackets--; 888 else 889 done = true; 890 break; 891 case TOKEN_PIPE: 892 if (parentheses == 0 && brackets == 0) 893 done = true; 894 break; 895 case TOKEN_END_OF_LINE: 896 done = true; 897 break; 898 } 899 } 900 901 int32 endPosition = fTokenizer.CurrentToken().position; 902 fTokenizer.RewindToken(); 903 904 // add the argument only, if it's not just all spaces 905 const char* arg = fTokenizer.String() + startPosition; 906 int32 argLen = endPosition - startPosition; 907 bool allSpaces = true; 908 for (int32 i = 0; allSpaces && i < argLen; i++) 909 allSpaces = isspace(arg[i]); 910 911 if (!allSpaces) 912 _AddArgument(argc, argv, arg, argLen); 913 } 914 915 916 void 917 ExpressionParser::_AddArgument(int& argc, char** argv, const char* argument, 918 int32 length) 919 { 920 if (argc == kMaxArgumentCount) 921 parse_exception("too many arguments for command", 0); 922 923 if (length < 0) 924 length = strlen(argument); 925 length++; 926 char* buffer = (char*)checked_malloc(length); 927 strlcpy(buffer, argument, length); 928 929 argv[argc++] = buffer; 930 } 931 932 933 uint64 934 ExpressionParser::_ParseSum(bool useValue, uint64 value) 935 { 936 if (!useValue) 937 value = _ParseProduct(); 938 939 while (true) { 940 const Token& token = fTokenizer.NextToken(); 941 switch (token.type) { 942 case TOKEN_PLUS: 943 value = value + _ParseProduct(); 944 break; 945 case TOKEN_MINUS: 946 value = value - _ParseProduct(); 947 break; 948 949 default: 950 fTokenizer.RewindToken(); 951 return value; 952 } 953 } 954 } 955 956 957 uint64 958 ExpressionParser::_ParseProduct() 959 { 960 uint64 value = _ParseUnary(); 961 962 while (true) { 963 Token token = fTokenizer.NextToken(); 964 switch (token.type) { 965 case TOKEN_STAR: 966 value = value * _ParseUnary(); 967 break; 968 case TOKEN_SLASH: { 969 uint64 rhs = _ParseUnary(); 970 if (rhs == 0) 971 parse_exception("division by zero", token.position); 972 value = value / rhs; 973 break; 974 } 975 case TOKEN_MODULO: { 976 uint64 rhs = _ParseUnary(); 977 if (rhs == 0) 978 parse_exception("modulo by zero", token.position); 979 value = value % rhs; 980 break; 981 } 982 983 default: 984 fTokenizer.RewindToken(); 985 return value; 986 } 987 } 988 } 989 990 991 uint64 992 ExpressionParser::_ParseUnary() 993 { 994 switch (fTokenizer.NextToken().type) { 995 case TOKEN_MINUS: 996 return -_ParseUnary(); 997 998 case TOKEN_STAR: 999 return _ParseDereference(NULL, NULL); 1000 1001 default: 1002 fTokenizer.RewindToken(); 1003 return _ParseAtom(); 1004 } 1005 1006 return 0; 1007 } 1008 1009 1010 uint64 1011 ExpressionParser::_ParseDereference(void** _address, uint32* _size) 1012 { 1013 int32 starPosition = fTokenizer.CurrentToken().position; 1014 1015 // optional "{ ... }" specifying the size to read 1016 uint64 size = 4; 1017 if (fTokenizer.NextToken().type == TOKEN_OPENING_BRACE) { 1018 int32 position = fTokenizer.CurrentToken().position; 1019 size = _ParseExpression(); 1020 1021 if (size != 1 && size != 2 && size != 4 && size != 8) { 1022 snprintf(sTempBuffer, sizeof(sTempBuffer), 1023 "invalid size (%llu) for unary * operator", size); 1024 parse_exception(sTempBuffer, position); 1025 } 1026 1027 _EatToken(TOKEN_CLOSING_BRACE); 1028 } else 1029 fTokenizer.RewindToken(); 1030 1031 const void* address = (const void*)(addr_t)_ParseUnary(); 1032 1033 // read bytes from address into a tempory buffer 1034 uint64 buffer; 1035 if (user_memcpy(&buffer, address, size) != B_OK) { 1036 snprintf(sTempBuffer, sizeof(sTempBuffer), 1037 "failed to dereference address %p", address); 1038 parse_exception(sTempBuffer, starPosition); 1039 } 1040 1041 // convert the value to uint64 1042 uint64 value = 0; 1043 switch (size) { 1044 case 1: 1045 value = *(uint8*)&buffer; 1046 break; 1047 case 2: 1048 value = *(uint16*)&buffer; 1049 break; 1050 case 4: 1051 value = *(uint32*)&buffer; 1052 break; 1053 case 8: 1054 value = buffer; 1055 break; 1056 } 1057 1058 if (_address != NULL) 1059 *_address = (void*)address; 1060 if (_size != NULL) 1061 *_size = size; 1062 1063 return value; 1064 } 1065 1066 1067 uint64 1068 ExpressionParser::_ParseAtom() 1069 { 1070 const Token& token = fTokenizer.NextToken(); 1071 if (token.type == TOKEN_END_OF_LINE) 1072 parse_exception("unexpected end of expression", token.position); 1073 1074 if (token.type == TOKEN_CONSTANT) 1075 return token.value; 1076 1077 if (token.type == TOKEN_IDENTIFIER) { 1078 if (!is_debug_variable_defined(token.string)) { 1079 snprintf(sTempBuffer, sizeof(sTempBuffer), 1080 "variable '%s' undefined", token.string); 1081 parse_exception(sTempBuffer, token.position); 1082 } 1083 1084 return get_debug_variable(token.string, 0); 1085 } 1086 1087 if (token.type == TOKEN_OPENING_PARENTHESIS) { 1088 uint64 value = _ParseExpression(); 1089 1090 _EatToken(TOKEN_CLOSING_PARENTHESIS); 1091 1092 return value; 1093 } 1094 1095 // it can only be a "[ command ]" expression now 1096 fTokenizer.RewindToken(); 1097 1098 _EatToken(TOKEN_OPENING_BRACKET); 1099 1100 fTokenizer.SetCommandMode(true); 1101 int returnValue; 1102 uint64 value = _ParseCommandPipe(returnValue); 1103 fTokenizer.SetCommandMode(false); 1104 1105 _EatToken(TOKEN_CLOSING_BRACKET); 1106 1107 return value; 1108 } 1109 1110 1111 const Token& 1112 ExpressionParser::_EatToken(int32 type) 1113 { 1114 const Token& token = fTokenizer.NextToken(); 1115 if (token.type != type) { 1116 snprintf(sTempBuffer, sizeof(sTempBuffer), "expected token type '%c', " 1117 "got token '%s'", char(type & ~TOKEN_FLAGS), token.string); 1118 parse_exception(sTempBuffer, token.position); 1119 } 1120 1121 return token; 1122 } 1123 1124 1125 1126 // #pragma mark - 1127 1128 1129 bool 1130 evaluate_debug_expression(const char* expression, uint64* _result, bool silent) 1131 { 1132 if (sNextJumpBufferIndex >= kJumpBufferCount) { 1133 kprintf_unfiltered("evaluate_debug_expression(): Out of jump buffers " 1134 "for exception handling\n"); 1135 return 0; 1136 } 1137 1138 bool success; 1139 uint64 result; 1140 DebugAllocPoolScope allocPoolScope; 1141 // Will clean up all allocations when we return. 1142 1143 if (setjmp(sJumpBuffers[sNextJumpBufferIndex++]) == 0) { 1144 result = ExpressionParser().EvaluateExpression(expression); 1145 success = true; 1146 } else { 1147 result = 0; 1148 success = false; 1149 if (!silent) { 1150 if (sExceptionPosition >= 0) { 1151 kprintf_unfiltered("%s, at position: %d, in expression: %s\n", 1152 sExceptionMessage, sExceptionPosition, expression); 1153 } else 1154 kprintf_unfiltered("%s", sExceptionMessage); 1155 } 1156 } 1157 1158 sNextJumpBufferIndex--; 1159 1160 if (success && _result != NULL) 1161 *_result = result; 1162 1163 return success; 1164 } 1165 1166 1167 int 1168 evaluate_debug_command(const char* commandLine) 1169 { 1170 if (sNextJumpBufferIndex >= kJumpBufferCount) { 1171 kprintf_unfiltered("evaluate_debug_command(): Out of jump buffers for " 1172 "exception handling\n"); 1173 return 0; 1174 } 1175 1176 int returnCode = 0; 1177 DebugAllocPoolScope allocPoolScope; 1178 // Will clean up all allocations when we return. 1179 1180 if (setjmp(sJumpBuffers[sNextJumpBufferIndex++]) == 0) { 1181 ExpressionParser().EvaluateCommand(commandLine, returnCode); 1182 } else { 1183 if (sExceptionPosition >= 0) { 1184 kprintf_unfiltered("%s, at position: %d, in command line: %s\n", 1185 sExceptionMessage, sExceptionPosition, commandLine); 1186 } else 1187 kprintf_unfiltered("%s", sExceptionMessage); 1188 } 1189 1190 sNextJumpBufferIndex--; 1191 1192 return returnCode; 1193 } 1194 1195 1196 status_t 1197 parse_next_debug_command_argument(const char** expressionString, char* buffer, 1198 size_t bufferSize) 1199 { 1200 if (sNextJumpBufferIndex >= kJumpBufferCount) { 1201 kprintf_unfiltered("parse_next_debug_command_argument(): Out of jump " 1202 "buffers for exception handling\n"); 1203 return B_ERROR; 1204 } 1205 1206 status_t error; 1207 DebugAllocPoolScope allocPoolScope; 1208 // Will clean up all allocations when we return. 1209 1210 if (setjmp(sJumpBuffers[sNextJumpBufferIndex++]) == 0) { 1211 error = ExpressionParser().ParseNextCommandArgument(expressionString, 1212 buffer, bufferSize); 1213 } else { 1214 if (sExceptionPosition >= 0) { 1215 kprintf_unfiltered("%s, at position: %d, in command line: %s\n", 1216 sExceptionMessage, sExceptionPosition, *expressionString); 1217 } else 1218 kprintf_unfiltered("%s", sExceptionMessage); 1219 error = B_BAD_VALUE; 1220 } 1221 1222 sNextJumpBufferIndex--; 1223 1224 return error; 1225 } 1226