1 /* 2 * Copyright 2008, 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_commands.h" 18 #include "debug_variables.h" 19 20 21 /* 22 Grammar: 23 24 commandLine := command | ( "(" expression ")" ) 25 expression := term | assignment 26 assignment := variable ( "=" | "+=" | "-=" | "*=" | "/=" | "%=" ) 27 expression 28 term := sum 29 sum := product ( ( "+" | "-" ) product )* 30 product := unary ( ( "*" | "/" | "%" ) unary )* 31 unary := atom | ( ( "-" | "*" [ "{" expression "}" ] ) unary ) 32 atom := variable | ( "(" expression ")" ) | ( "[" command "]" ) 33 variable := identifier 34 identifier := ( "_" | "a" - "z" | "A" - "Z" ) 35 ( "_" | "a" - "z" | "A" - "Z" | "0" - "9" )* 36 command := identifier argument* 37 argument := ( "(" expression ")" ) | ( "[" commandLine "]" ) 38 | unquotedString | quotedString 39 */ 40 41 42 static const int kMaxTokenLength = 128; 43 static const int kJumpBufferCount = 10; 44 45 static const int kMaxArgumentCount = 64; 46 static const size_t kTemporaryStorageSize = 10240; 47 48 static jmp_buf sJumpBuffers[kJumpBufferCount]; 49 static int sNextJumpBufferIndex = 0; 50 51 static char sExceptionMessage[128]; 52 static int sExceptionPosition; 53 54 static char sTempBuffer[128]; 55 // for composing debug output etc. 56 57 // temporary storage for command argument vectors and the arguments itself 58 static uint8 sTemporaryStorage[kTemporaryStorageSize]; 59 static size_t sTemporaryStorageUsed = 0; 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_STRING = '"', 91 TOKEN_UNKNOWN = '?', 92 TOKEN_NONE = ' ', 93 TOKEN_END_OF_LINE = '\n', 94 }; 95 96 struct Token { 97 char string[kMaxTokenLength]; 98 uint64 value; 99 int32 type; 100 int32 position; 101 102 void SetTo(const char* string, int32 length, int32 position, int32 type) 103 { 104 length = min_c((size_t)length, (sizeof(this->string) - 1)); 105 strlcpy(this->string, string, length + 1); 106 this->type = type; 107 this->value = 0; 108 this->position = position; 109 } 110 111 void Unset() 112 { 113 string[0] = '\0'; 114 value = 0; 115 type = TOKEN_NONE; 116 position = 0; 117 } 118 }; 119 120 121 // #pragma mark - exceptions 122 123 124 static void 125 parse_exception(const char* message, int32 position) 126 { 127 if (sNextJumpBufferIndex == 0) { 128 kprintf("parse_exception(): No jump buffer!\n"); 129 kprintf("exception: \"%s\", position: %lu\n", message, position); 130 return; 131 } 132 133 strlcpy(sExceptionMessage, message, sizeof(sExceptionMessage)); 134 sExceptionPosition = position; 135 136 longjmp(sJumpBuffers[sNextJumpBufferIndex - 1], 1); 137 } 138 139 140 // #pragma mark - temporary storage 141 142 143 static void* 144 allocate_temp_storage(size_t size) 145 { 146 // 8 byte align 147 size = (size + 7) & ~7; 148 149 if (sTemporaryStorageUsed + size > kTemporaryStorageSize) { 150 parse_exception("out of temporary storage for command execution", -1); 151 return NULL; 152 } 153 154 void* buffer = sTemporaryStorage + sTemporaryStorageUsed; 155 sTemporaryStorageUsed += size; 156 157 return buffer; 158 } 159 160 161 static void 162 free_temp_storage(void* _buffer) 163 { 164 uint8* buffer = (uint8*)_buffer; 165 166 if (buffer == NULL) 167 return; 168 169 // must be freed in the reverse allocation order 170 if (buffer < sTemporaryStorage 171 || buffer > sTemporaryStorage + sTemporaryStorageUsed) { 172 panic("Invalid pointer passed to free_temp_storage(): %p, temp " 173 "storage base: %p", buffer, sTemporaryStorage); 174 return; 175 } 176 177 sTemporaryStorageUsed = buffer - sTemporaryStorage; 178 } 179 180 181 // #pragma mark - Tokenizer 182 183 184 class Tokenizer { 185 public: 186 Tokenizer(const char* string) 187 : fCommandMode(false) 188 { 189 SetTo(string); 190 } 191 192 void SetTo(const char* string) 193 { 194 fString = fCurrentChar = string; 195 fCurrentToken.Unset(); 196 fReuseToken = false; 197 } 198 199 void SetPosition(int32 position) 200 { 201 fCurrentChar = fString + position; 202 fCurrentToken.Unset(); 203 fReuseToken = false; 204 } 205 206 void SetCommandMode(bool commandMode) 207 { 208 fCommandMode = commandMode; 209 } 210 211 const char* String() const 212 { 213 return fString; 214 } 215 216 const Token& NextToken() 217 { 218 if (fCurrentToken.type == TOKEN_END_OF_LINE) 219 return fCurrentToken; 220 221 if (fReuseToken) { 222 fReuseToken = false; 223 return fCurrentToken; 224 } 225 226 while (*fCurrentChar != 0 && isspace(*fCurrentChar)) 227 fCurrentChar++; 228 229 if (*fCurrentChar == 0) { 230 fCurrentToken.SetTo("", 0, _CurrentPos(), TOKEN_END_OF_LINE); 231 return fCurrentToken; 232 } 233 234 return (fCommandMode ? _NextTokenCommand() : _NextTokenExpression()); 235 } 236 237 const Token& CurrentToken() const 238 { 239 return fCurrentToken; 240 } 241 242 void RewindToken() 243 { 244 fReuseToken = true; 245 } 246 247 private: 248 const Token& _NextTokenExpression() 249 { 250 if (isdigit(*fCurrentChar)) { 251 // number 252 const char* begin = fCurrentChar++; 253 254 if (*fCurrentChar == 'x') { 255 // hex number 256 fCurrentChar++; 257 while (*fCurrentChar != 0 258 && (isdigit(*fCurrentChar) 259 || strchr("abcdefABCDEF", *fCurrentChar))) { 260 fCurrentChar++; 261 } 262 263 if (fCurrentChar - begin == 2) 264 parse_exception("invalid hex number", begin - fString); 265 266 } else { 267 // decimal number 268 while (*fCurrentChar != 0 && isdigit(*fCurrentChar)) 269 fCurrentChar++; 270 } 271 272 int32 length = fCurrentChar - begin; 273 fCurrentToken.SetTo(begin, length, _CurrentPos() - length, 274 TOKEN_CONSTANT); 275 fCurrentToken.value = strtoull(fCurrentToken.string, NULL, 0); 276 277 } else if (isalpha(*fCurrentChar) || *fCurrentChar == '_') { 278 // identifier 279 const char* begin = fCurrentChar; 280 while (*fCurrentChar != 0 281 && (isalpha(*fCurrentChar) || *fCurrentChar == '_' 282 || isdigit(*fCurrentChar))) { 283 fCurrentChar++; 284 } 285 286 int32 length = fCurrentChar - begin; 287 fCurrentToken.SetTo(begin, length, _CurrentPos() - length, 288 TOKEN_IDENTIFIER); 289 290 } else { 291 const char* begin = fCurrentChar; 292 char c = *fCurrentChar; 293 fCurrentChar++; 294 int32 flags = 0; 295 296 switch (c) { 297 case '=': 298 fCurrentChar--; 299 case '+': 300 case '-': 301 case '*': 302 case '/': 303 case '%': 304 if (*fCurrentChar == '=') { 305 fCurrentChar++; 306 flags = TOKEN_ASSIGN_FLAG; 307 } 308 309 case '(': 310 case ')': 311 case '[': 312 case ']': 313 case '{': 314 case '}': 315 { 316 int32 length = fCurrentChar - begin; 317 fCurrentToken.SetTo(begin, length, _CurrentPos() - length, 318 c | flags); 319 break; 320 } 321 322 case '"': 323 { 324 fCurrentChar--; 325 _QuotedString(); 326 break; 327 } 328 329 default: 330 { 331 fCurrentChar--; 332 _UnquotedString(); 333 break; 334 } 335 } 336 } 337 338 return fCurrentToken; 339 } 340 341 const Token& _NextTokenCommand() 342 { 343 switch (*fCurrentChar) { 344 case '(': 345 case ')': 346 case '[': 347 case ']': 348 fCurrentToken.SetTo(fCurrentChar, 1, _CurrentPos(), 349 *fCurrentChar); 350 fCurrentChar++; 351 return fCurrentToken; 352 case '"': 353 return _QuotedString(); 354 355 default: 356 return _UnquotedString(); 357 } 358 } 359 360 const Token& _QuotedString() 361 { 362 const char* begin = fCurrentChar++; 363 int32 length = 0; 364 365 while (*fCurrentChar != '\0' && *fCurrentChar != '"') { 366 char c = *fCurrentChar; 367 fCurrentChar++; 368 369 if (c == '\\') { 370 // an escaped char 371 c = *fCurrentChar; 372 fCurrentChar++; 373 374 if (c == '\0') 375 break; 376 } 377 378 if ((size_t)length 379 >= sizeof(fCurrentToken.string) - 1) { 380 parse_exception("quoted string too long", begin - fString); 381 } 382 383 fCurrentToken.string[length++] = c; 384 } 385 386 if (*fCurrentChar == '\0') { 387 parse_exception("unexpected end of line while " 388 "parsing quoted string", begin - fString); 389 } 390 391 fCurrentChar++; 392 393 fCurrentToken.string[length] = '\0'; 394 fCurrentToken.value = 0; 395 fCurrentToken.type = TOKEN_STRING; 396 fCurrentToken.position = begin - fString; 397 398 return fCurrentToken; 399 } 400 401 const Token& _UnquotedString() 402 { 403 const char* begin = fCurrentChar; 404 405 while (*fCurrentChar != 0 && !_IsUnquotedDelimitingChar(*fCurrentChar)) 406 fCurrentChar++; 407 408 int32 length = fCurrentChar - begin; 409 fCurrentToken.SetTo(begin, length, _CurrentPos() - length, 410 TOKEN_UNKNOWN); 411 412 return fCurrentToken; 413 } 414 415 bool _IsUnquotedDelimitingChar(char c) 416 { 417 if (isspace(c)) 418 return true; 419 420 switch (c) { 421 case '(': 422 case ')': 423 case '[': 424 case ']': 425 case '"': 426 return true; 427 428 case '{': 429 case '}': 430 case '=': 431 case '+': 432 case '-': 433 case '*': 434 case '/': 435 case '%': 436 return !fCommandMode; 437 438 default: 439 return false; 440 } 441 } 442 443 int32 _CurrentPos() const 444 { 445 return fCurrentChar - fString; 446 } 447 448 private: 449 const char* fString; 450 const char* fCurrentChar; 451 Token fCurrentToken; 452 bool fReuseToken; 453 bool fCommandMode; 454 }; 455 456 457 // #pragma mark - ExpressionParser 458 459 460 class ExpressionParser { 461 public: 462 ExpressionParser(); 463 ~ExpressionParser(); 464 465 uint64 EvaluateExpression( 466 const char* expressionString); 467 uint64 EvaluateCommand( 468 const char* expressionString, 469 int& returnCode); 470 471 private: 472 uint64 _ParseExpression(); 473 uint64 _ParseCommand(int& returnCode); 474 bool _ParseArgument(int& argc, char** argv); 475 void _GetUnparsedArgument(int& argc, char** argv); 476 void _AddArgument(int& argc, char** argv, 477 const char* argument, int32 length = -1); 478 uint64 _ParseSum(); 479 uint64 _ParseProduct(); 480 uint64 _ParsePower(); 481 uint64 _ParseUnary(); 482 uint64 _ParseAtom(); 483 484 const Token& _EatToken(int32 type); 485 486 Tokenizer fTokenizer; 487 }; 488 489 490 ExpressionParser::ExpressionParser() 491 : fTokenizer("") 492 { 493 } 494 495 496 ExpressionParser::~ExpressionParser() 497 { 498 } 499 500 501 uint64 502 ExpressionParser::EvaluateExpression(const char* expressionString) 503 { 504 fTokenizer.SetTo(expressionString); 505 506 uint64 value = _ParseExpression(); 507 const Token& token = fTokenizer.NextToken(); 508 if (token.type != TOKEN_END_OF_LINE) 509 parse_exception("parse error", token.position); 510 511 return value; 512 } 513 514 515 uint64 516 ExpressionParser::EvaluateCommand(const char* expressionString, 517 int& returnCode) 518 { 519 fTokenizer.SetTo(expressionString); 520 521 // Allowed is not only a command, but also an assignment. Either starts with 522 // an identifier. 523 _EatToken(TOKEN_IDENTIFIER); 524 525 uint64 value; 526 const Token& token = fTokenizer.NextToken(); 527 if (token.type & TOKEN_ASSIGN_FLAG) { 528 // an assignment 529 fTokenizer.SetTo(expressionString); 530 value = _ParseExpression(); 531 returnCode = 0; 532 } else { 533 // no assignment, so let's assume it's a command 534 fTokenizer.SetTo(expressionString); 535 fTokenizer.SetCommandMode(true); 536 value = _ParseCommand(returnCode); 537 } 538 539 if (token.type != TOKEN_END_OF_LINE) 540 parse_exception("parse error", token.position); 541 542 return value; 543 } 544 545 546 uint64 547 ExpressionParser::_ParseExpression() 548 { 549 const Token& token = fTokenizer.NextToken(); 550 int32 position = token.position; 551 if (token.type == TOKEN_IDENTIFIER) { 552 char variable[MAX_DEBUG_VARIABLE_NAME_LEN]; 553 strlcpy(variable, token.string, sizeof(variable)); 554 555 int32 assignmentType = fTokenizer.NextToken().type; 556 if (assignmentType & TOKEN_ASSIGN_FLAG) { 557 // an assignment 558 uint64 rhs = _ParseExpression(); 559 560 // handle the standard assignment separately -- the other kinds 561 // need the variable to be defined 562 if (assignmentType == TOKEN_ASSIGN) { 563 if (!set_debug_variable(variable, rhs)) { 564 snprintf(sTempBuffer, sizeof(sTempBuffer), 565 "failed to set value for variable \"%s\"", 566 variable); 567 parse_exception(sTempBuffer, position); 568 } 569 570 return rhs; 571 } 572 573 // variable must be defined 574 if (!is_debug_variable_defined(variable)) { 575 snprintf(sTempBuffer, sizeof(sTempBuffer), 576 "variable \"%s\" not defined in modifying assignment", 577 variable); 578 parse_exception(sTempBuffer, position); 579 } 580 581 uint64 variableValue = get_debug_variable(variable, 0); 582 583 // check for division by zero for the respective assignment types 584 if ((assignmentType == TOKEN_SLASH_ASSIGN 585 || assignmentType == TOKEN_MODULO_ASSIGN) 586 && rhs == 0) { 587 parse_exception("division by zero", position); 588 } 589 590 // compute the new variable value 591 switch (assignmentType) { 592 case TOKEN_PLUS_ASSIGN: 593 variableValue += rhs; 594 break; 595 case TOKEN_MINUS_ASSIGN: 596 variableValue -= rhs; 597 break; 598 case TOKEN_STAR_ASSIGN: 599 variableValue *= rhs; 600 break; 601 case TOKEN_SLASH_ASSIGN: 602 variableValue /= rhs; 603 break; 604 case TOKEN_MODULO_ASSIGN: 605 variableValue %= rhs; 606 break; 607 default: 608 fTokenizer.SetPosition(position); 609 return _ParseSum(); 610 } 611 612 set_debug_variable(variable, variableValue); 613 return variableValue; 614 } 615 } 616 617 // no assignment -- reset to the identifier position and parse a sum 618 fTokenizer.SetPosition(position); 619 return _ParseSum(); 620 } 621 622 623 uint64 624 ExpressionParser::_ParseCommand(int& returnCode) 625 { 626 fTokenizer.SetCommandMode(false); 627 const Token& token = _EatToken(TOKEN_IDENTIFIER); 628 fTokenizer.SetCommandMode(true); 629 630 bool ambiguous; 631 debugger_command* command = find_debugger_command(token.string, true, 632 ambiguous); 633 634 if (command == NULL) { 635 if (ambiguous) { 636 snprintf(sTempBuffer, sizeof(sTempBuffer), 637 "Ambiguous command \"%s\". Use tab completion or enter " 638 "\"help %s\" get a list of matching commands.\n", token.string, 639 token.string); 640 } else { 641 snprintf(sTempBuffer, sizeof(sTempBuffer), 642 "Unknown command \"%s\". Enter \"help\" to get a list of " 643 "all supported commands.\n", token.string); 644 } 645 646 parse_exception(sTempBuffer, -1); 647 } 648 649 // allocate temporary buffer for the argument vector 650 char** argv = (char**)allocate_temp_storage( 651 kMaxArgumentCount * sizeof(char*)); 652 int argc = 0; 653 argv[argc++] = (char*)command->name; 654 655 // get the arguments 656 if ((command->flags & B_KDEBUG_DONT_PARSE_ARGUMENTS) != 0) { 657 _GetUnparsedArgument(argc, argv); 658 } else { 659 while (fTokenizer.NextToken().type != TOKEN_END_OF_LINE) { 660 fTokenizer.RewindToken(); 661 if (!_ParseArgument(argc, argv)) 662 break; 663 } 664 } 665 666 // invoke the command 667 returnCode = invoke_debugger_command(command, argc, argv); 668 669 free_temp_storage(argv); 670 671 return get_debug_variable("_", 0); 672 } 673 674 675 bool 676 ExpressionParser::_ParseArgument(int& argc, char** argv) 677 { 678 const Token& token = fTokenizer.NextToken(); 679 switch (token.type) { 680 case TOKEN_OPENING_PARENTHESIS: 681 { 682 // this starts an expression 683 fTokenizer.SetCommandMode(false); 684 uint64 value = _ParseExpression(); 685 fTokenizer.SetCommandMode(true); 686 _EatToken(TOKEN_CLOSING_PARENTHESIS); 687 688 snprintf(sTempBuffer, sizeof(sTempBuffer), "%llu", value); 689 _AddArgument(argc, argv, sTempBuffer); 690 return true; 691 } 692 693 case TOKEN_OPENING_BRACKET: 694 { 695 // this starts a sub command 696 int returnValue; 697 uint64 value = _ParseCommand(returnValue); 698 _EatToken(TOKEN_CLOSING_BRACKET); 699 700 snprintf(sTempBuffer, sizeof(sTempBuffer), "%llu", value); 701 _AddArgument(argc, argv, sTempBuffer); 702 return true; 703 } 704 705 case TOKEN_STRING: 706 case TOKEN_UNKNOWN: 707 _AddArgument(argc, argv, token.string); 708 return true; 709 710 case TOKEN_CLOSING_PARENTHESIS: 711 case TOKEN_CLOSING_BRACKET: 712 // those don't belong to us 713 fTokenizer.RewindToken(); 714 return false; 715 716 default: 717 { 718 snprintf(sTempBuffer, sizeof(sTempBuffer), "unexpected token " 719 "\"%s\"", token.string); 720 parse_exception(sTempBuffer, token.position); 721 return false; 722 } 723 } 724 } 725 726 727 void 728 ExpressionParser::_GetUnparsedArgument(int& argc, char** argv) 729 { 730 int32 startPosition = fTokenizer.NextToken().position; 731 fTokenizer.RewindToken(); 732 733 // match parentheses and brackets, but otherwise skip all tokens 734 int32 parentheses = 0; 735 int32 brackets = 0; 736 bool done = false; 737 while (!done) { 738 const Token& token = fTokenizer.NextToken(); 739 switch (token.type) { 740 case TOKEN_OPENING_PARENTHESIS: 741 parentheses++; 742 break; 743 case TOKEN_OPENING_BRACKET: 744 brackets++; 745 break; 746 case TOKEN_CLOSING_PARENTHESIS: 747 if (parentheses > 0) 748 parentheses--; 749 else 750 done = true; 751 break; 752 case TOKEN_CLOSING_BRACKET: 753 if (brackets > 0) 754 brackets--; 755 else 756 done = true; 757 break; 758 case TOKEN_END_OF_LINE: 759 done = true; 760 break; 761 } 762 } 763 764 int32 endPosition = fTokenizer.CurrentToken().position; 765 fTokenizer.RewindToken(); 766 767 _AddArgument(argc, argv, fTokenizer.String() + startPosition, 768 endPosition - startPosition); 769 } 770 771 772 void 773 ExpressionParser::_AddArgument(int& argc, char** argv, const char* argument, 774 int32 length) 775 { 776 if (argc == kMaxArgumentCount) 777 parse_exception("too many arguments for command", 0); 778 779 if (length < 0) 780 length = strlen(argument); 781 length++; 782 char* buffer = (char*)allocate_temp_storage(length); 783 strlcpy(buffer, argument, length); 784 785 argv[argc++] = buffer; 786 } 787 788 789 uint64 790 ExpressionParser::_ParseSum() 791 { 792 uint64 value = _ParseProduct(); 793 794 while (true) { 795 const Token& token = fTokenizer.NextToken(); 796 switch (token.type) { 797 case TOKEN_PLUS: 798 value = value + _ParseProduct(); 799 break; 800 case TOKEN_MINUS: 801 value = value - _ParseProduct(); 802 break; 803 804 default: 805 fTokenizer.RewindToken(); 806 return value; 807 } 808 } 809 } 810 811 812 uint64 813 ExpressionParser::_ParseProduct() 814 { 815 uint64 value = _ParseUnary(); 816 817 while (true) { 818 Token token = fTokenizer.NextToken(); 819 switch (token.type) { 820 case TOKEN_STAR: 821 value = value * _ParseUnary(); 822 break; 823 case TOKEN_SLASH: { 824 uint64 rhs = _ParseUnary(); 825 if (rhs == 0) 826 parse_exception("division by zero", token.position); 827 value = value / rhs; 828 break; 829 } 830 case TOKEN_MODULO: { 831 uint64 rhs = _ParseUnary(); 832 if (rhs == 0) 833 parse_exception("modulo by zero", token.position); 834 value = value % rhs; 835 break; 836 } 837 838 default: 839 fTokenizer.RewindToken(); 840 return value; 841 } 842 } 843 } 844 845 846 uint64 847 ExpressionParser::_ParseUnary() 848 { 849 switch (fTokenizer.NextToken().type) { 850 case TOKEN_MINUS: 851 return -_ParseUnary(); 852 853 case TOKEN_STAR: 854 { 855 int32 starPosition = fTokenizer.CurrentToken().position; 856 857 // optional "{ ... }" specifying the size to read 858 uint64 size = 4; 859 if (fTokenizer.NextToken().type == TOKEN_OPENING_BRACE) { 860 int32 position = fTokenizer.CurrentToken().position; 861 size = _ParseExpression(); 862 863 if (size != 1 && size != 2 && size != 4 && size != 8) { 864 snprintf(sTempBuffer, sizeof(sTempBuffer), 865 "invalid size (%llu) for unary * operator", size); 866 parse_exception(sTempBuffer, position); 867 } 868 869 _EatToken(TOKEN_CLOSING_BRACE); 870 } else 871 fTokenizer.RewindToken(); 872 873 const void* address = (const void*)(addr_t)_ParseUnary(); 874 875 // read bytes from address into a tempory buffer 876 uint64 buffer; 877 if (user_memcpy(&buffer, address, size) != B_OK) { 878 snprintf(sTempBuffer, sizeof(sTempBuffer), 879 "failed to dereference address %p", address); 880 parse_exception(sTempBuffer, starPosition); 881 } 882 883 // convert the value to uint64 884 uint64 value = 0; 885 switch (size) { 886 case 1: 887 value = *(uint8*)&buffer; 888 break; 889 case 2: 890 value = *(uint16*)&buffer; 891 break; 892 case 4: 893 value = *(uint32*)&buffer; 894 break; 895 case 8: 896 value = buffer; 897 break; 898 } 899 900 return value; 901 } 902 903 default: 904 fTokenizer.RewindToken(); 905 return _ParseAtom(); 906 } 907 908 return 0; 909 } 910 911 912 uint64 913 ExpressionParser::_ParseAtom() 914 { 915 const Token& token = fTokenizer.NextToken(); 916 if (token.type == TOKEN_END_OF_LINE) 917 parse_exception("unexpected end of expression", token.position); 918 919 if (token.type == TOKEN_CONSTANT) 920 return token.value; 921 922 if (token.type == TOKEN_IDENTIFIER) { 923 if (!is_debug_variable_defined(token.string)) { 924 snprintf(sTempBuffer, sizeof(sTempBuffer), 925 "variable '%s' undefined", token.string); 926 parse_exception(sTempBuffer, token.position); 927 } 928 929 return get_debug_variable(token.string, 0); 930 } 931 932 if (token.type == TOKEN_OPENING_PARENTHESIS) { 933 uint64 value = _ParseExpression(); 934 935 _EatToken(TOKEN_CLOSING_PARENTHESIS); 936 937 return value; 938 } 939 940 // it can only be a "[ command ]" expression now 941 fTokenizer.RewindToken(); 942 943 _EatToken(TOKEN_OPENING_BRACKET); 944 945 fTokenizer.SetCommandMode(true); 946 int returnValue; 947 uint64 value = _ParseCommand(returnValue); 948 fTokenizer.SetCommandMode(false); 949 950 _EatToken(TOKEN_CLOSING_BRACKET); 951 952 return value; 953 } 954 955 956 const Token& 957 ExpressionParser::_EatToken(int32 type) 958 { 959 const Token& token = fTokenizer.NextToken(); 960 if (token.type != type) { 961 snprintf(sTempBuffer, sizeof(sTempBuffer), "expected token type '%c', " 962 "got token '%s'", char(type & ~TOKEN_FLAGS), token.string); 963 parse_exception(sTempBuffer, token.position); 964 } 965 966 return token; 967 } 968 969 970 971 // #pragma mark - 972 973 974 bool 975 evaluate_debug_expression(const char* expression, uint64* _result, bool silent) 976 { 977 if (sNextJumpBufferIndex >= kJumpBufferCount) { 978 kprintf("evaluate_debug_expression(): Out of jump buffers for " 979 "exception handling\n"); 980 return 0; 981 } 982 983 bool success; 984 uint64 result; 985 void* temporaryStorageMark = allocate_temp_storage(0); 986 // get a temporary storage mark, so we can cleanup everything that 987 // is allocated during the evaluation 988 989 if (setjmp(sJumpBuffers[sNextJumpBufferIndex++]) == 0) { 990 result = ExpressionParser().EvaluateExpression(expression); 991 success = true; 992 } else { 993 result = 0; 994 success = false; 995 if (!silent) { 996 if (sExceptionPosition >= 0) { 997 kprintf("%s, at position: %d, in expression: %s\n", 998 sExceptionMessage, sExceptionPosition, expression); 999 } else 1000 kprintf("%s", sExceptionMessage); 1001 } 1002 } 1003 1004 sNextJumpBufferIndex--; 1005 1006 // cleanup temp allocations 1007 free_temp_storage(temporaryStorageMark); 1008 1009 if (success && _result != NULL) 1010 *_result = result; 1011 1012 return success; 1013 } 1014 1015 1016 int 1017 evaluate_debug_command(const char* commandLine) 1018 { 1019 if (sNextJumpBufferIndex >= kJumpBufferCount) { 1020 kprintf("evaluate_debug_command(): Out of jump buffers for " 1021 "exception handling\n"); 1022 return 0; 1023 } 1024 1025 int returnCode = 0; 1026 void* temporaryStorageMark = allocate_temp_storage(0); 1027 // get a temporary storage mark, so we can cleanup everything that 1028 // is allocated during the evaluation 1029 1030 if (setjmp(sJumpBuffers[sNextJumpBufferIndex++]) == 0) { 1031 ExpressionParser().EvaluateCommand(commandLine, returnCode); 1032 } else { 1033 if (sExceptionPosition >= 0) { 1034 kprintf("%s, at position: %d, in command line: %s\n", 1035 sExceptionMessage, sExceptionPosition, commandLine); 1036 } else 1037 kprintf("%s", sExceptionMessage); 1038 } 1039 1040 sNextJumpBufferIndex--; 1041 1042 // cleanup temp allocations 1043 free_temp_storage(temporaryStorageMark); 1044 1045 return returnCode; 1046 } 1047