void ExpressionParser::_GetUnparsedArgument(int& argc, char** argv) { int32 startPosition = fTokenizer.NextToken().position; fTokenizer.RewindToken(); // match parentheses and brackets, but otherwise skip all tokens int32 parentheses = 0; int32 brackets = 0; bool done = false; while (!done) { const Token& token = fTokenizer.NextToken(); switch (token.type) { case TOKEN_OPENING_PARENTHESIS: parentheses++; break; case TOKEN_OPENING_BRACKET: brackets++; break; case TOKEN_CLOSING_PARENTHESIS: if (parentheses > 0) parentheses--; else done = true; break; case TOKEN_CLOSING_BRACKET: if (brackets > 0) brackets--; else done = true; break; case TOKEN_PIPE: case TOKEN_SEMICOLON: if (parentheses == 0 && brackets == 0) done = true; break; case TOKEN_END_OF_LINE: done = true; break; } } int32 endPosition = fTokenizer.CurrentToken().position; fTokenizer.RewindToken(); // add the argument only, if it's not just all spaces const char* arg = fTokenizer.String() + startPosition; int32 argLen = endPosition - startPosition; bool allSpaces = true; for (int32 i = 0; allSpaces && i < argLen; i++) allSpaces = isspace(arg[i]); if (!allSpaces) _AddArgument(argc, argv, arg, argLen); }
uint64 ExpressionParser::_ParseProduct() { uint64 value = _ParseUnary(); while (true) { Token token = fTokenizer.NextToken(); switch (token.type) { case TOKEN_STAR: value = value * _ParseUnary(); break; case TOKEN_SLASH: { uint64 rhs = _ParseUnary(); if (rhs == 0) parse_exception("division by zero", token.position); value = value / rhs; break; } case TOKEN_MODULO: { uint64 rhs = _ParseUnary(); if (rhs == 0) parse_exception("modulo by zero", token.position); value = value % rhs; break; } default: fTokenizer.RewindToken(); return value; } } }
uint64 ExpressionParser::_ParseCommandPipe(int& returnCode) { debugger_command_pipe* pipe = (debugger_command_pipe*)checked_malloc( sizeof(debugger_command_pipe)); pipe->segment_count = 0; pipe->broken = false; do { if (pipe->segment_count >= MAX_DEBUGGER_COMMAND_PIPE_LENGTH) parse_exception("Pipe too long", fTokenizer.NextToken().position); debugger_command_pipe_segment& segment = pipe->segments[pipe->segment_count]; segment.index = pipe->segment_count++; _ParseCommand(segment); } while (fTokenizer.NextToken().type == TOKEN_PIPE); fTokenizer.RewindToken(); // invoke the pipe returnCode = invoke_debugger_command_pipe(pipe); debug_free(pipe); return get_debug_variable("_", 0); }
status_t ExpressionParser::ParseNextCommandArgument(const char** expressionString, char* buffer, size_t bufferSize) { fTokenizer.SetTo(*expressionString); fTokenizer.SetCommandMode(true); if (fTokenizer.NextToken().type == TOKEN_END_OF_LINE) return B_ENTRY_NOT_FOUND; fTokenizer.RewindToken(); char* argv[2]; int argc = 0; if (!_ParseArgument(argc, argv)) return B_BAD_VALUE; strlcpy(buffer, argv[0], bufferSize); const Token& token = fTokenizer.NextToken(); if (token.type == TOKEN_END_OF_LINE) *expressionString = NULL; else *expressionString += token.position; return B_OK; }
uint64 ExpressionParser::_ParseDereference(void** _address, uint32* _size) { int32 starPosition = fTokenizer.CurrentToken().position; // optional "{ ... }" specifying the size to read uint64 size = 4; if (fTokenizer.NextToken().type == TOKEN_OPENING_BRACE) { int32 position = fTokenizer.CurrentToken().position; size = _ParseExpression(); if (size != 1 && size != 2 && size != 4 && size != 8) { snprintf(sTempBuffer, sizeof(sTempBuffer), "invalid size (%" B_PRIu64 ") for unary * operator", size); parse_exception(sTempBuffer, position); } _EatToken(TOKEN_CLOSING_BRACE); } else fTokenizer.RewindToken(); const void* address = (const void*)(addr_t)_ParseUnary(); // read bytes from address into a tempory buffer uint64 buffer; if (debug_memcpy(B_CURRENT_TEAM, &buffer, address, size) != B_OK) { snprintf(sTempBuffer, sizeof(sTempBuffer), "failed to dereference address %p", address); parse_exception(sTempBuffer, starPosition); } // convert the value to uint64 uint64 value = 0; switch (size) { case 1: value = *(uint8*)&buffer; break; case 2: value = *(uint16*)&buffer; break; case 4: value = *(uint32*)&buffer; break; case 8: value = buffer; break; } if (_address != NULL) *_address = (void*)address; if (_size != NULL) *_size = size; return value; }
void ExpressionParser::_ParseCommand(debugger_command_pipe_segment& segment) { fTokenizer.SetCommandMode(false); const Token& token = _EatToken(TOKEN_IDENTIFIER); fTokenizer.SetCommandMode(true); bool ambiguous; debugger_command* command = find_debugger_command(token.string, true, ambiguous); if (command == NULL) { if (ambiguous) { snprintf(sTempBuffer, sizeof(sTempBuffer), "Ambiguous command \"%s\". Use tab completion or enter " "\"help %s\" get a list of matching commands.\n", token.string, token.string); } else { snprintf(sTempBuffer, sizeof(sTempBuffer), "Unknown command \"%s\". Enter \"help\" to get a list of " "all supported commands.\n", token.string); } parse_exception(sTempBuffer, -1); } // allocate temporary buffer for the argument vector char** argv = (char**)checked_malloc(kMaxArgumentCount * sizeof(char*)); int argc = 0; argv[argc++] = (char*)command->name; // get the arguments if ((command->flags & B_KDEBUG_DONT_PARSE_ARGUMENTS) != 0) { _GetUnparsedArgument(argc, argv); } else { while (fTokenizer.NextToken().type != TOKEN_END_OF_LINE) { fTokenizer.RewindToken(); if (!_ParseArgument(argc, argv)) break; } } if (segment.index > 0) { if (argc >= kMaxArgumentCount) parse_exception("too many arguments for command", 0); else argc++; } segment.command = command; segment.argc = argc; segment.argv = argv; segment.invocations = 0; }
bool ExpressionParser::_ParseArgument(int& argc, char** argv) { const Token& token = fTokenizer.NextToken(); switch (token.type) { case TOKEN_OPENING_PARENTHESIS: { // this starts an expression fTokenizer.SetCommandMode(false); uint64 value = _ParseExpression(); fTokenizer.SetCommandMode(true); _EatToken(TOKEN_CLOSING_PARENTHESIS); snprintf(sTempBuffer, sizeof(sTempBuffer), "%" B_PRIu64, value); _AddArgument(argc, argv, sTempBuffer); return true; } case TOKEN_OPENING_BRACKET: { // this starts a sub command int returnValue; uint64 value = _ParseCommandPipe(returnValue); _EatToken(TOKEN_CLOSING_BRACKET); snprintf(sTempBuffer, sizeof(sTempBuffer), "%" B_PRIu64, value); _AddArgument(argc, argv, sTempBuffer); return true; } case TOKEN_STRING: case TOKEN_UNKNOWN: _AddArgument(argc, argv, token.string); return true; case TOKEN_CLOSING_PARENTHESIS: case TOKEN_CLOSING_BRACKET: case TOKEN_PIPE: case TOKEN_SEMICOLON: // those don't belong to us fTokenizer.RewindToken(); return false; default: { snprintf(sTempBuffer, sizeof(sTempBuffer), "unexpected token " "\"%s\"", token.string); parse_exception(sTempBuffer, token.position); return false; } } }
uint64 ExpressionParser::_ParseUnary() { switch (fTokenizer.NextToken().type) { case TOKEN_MINUS: return -_ParseUnary(); case TOKEN_STAR: return _ParseDereference(NULL, NULL); default: fTokenizer.RewindToken(); return _ParseAtom(); } return 0; }
uint64 ExpressionParser::_ParseAtom() { const Token& token = fTokenizer.NextToken(); if (token.type == TOKEN_END_OF_LINE) parse_exception("unexpected end of expression", token.position); if (token.type == TOKEN_CONSTANT) return token.value; if (token.type == TOKEN_IDENTIFIER) { if (!is_debug_variable_defined(token.string)) { snprintf(sTempBuffer, sizeof(sTempBuffer), "variable '%s' undefined", token.string); parse_exception(sTempBuffer, token.position); } return get_debug_variable(token.string, 0); } if (token.type == TOKEN_OPENING_PARENTHESIS) { uint64 value = _ParseExpression(); _EatToken(TOKEN_CLOSING_PARENTHESIS); return value; } // it can only be a "[ command ]" expression now fTokenizer.RewindToken(); _EatToken(TOKEN_OPENING_BRACKET); fTokenizer.SetCommandMode(true); int returnValue; uint64 value = _ParseCommandPipe(returnValue); fTokenizer.SetCommandMode(false); _EatToken(TOKEN_CLOSING_BRACKET); return value; }
uint64 ExpressionParser::_ParseSum(bool useValue, uint64 value) { if (!useValue) value = _ParseProduct(); while (true) { const Token& token = fTokenizer.NextToken(); switch (token.type) { case TOKEN_PLUS: value = value + _ParseProduct(); break; case TOKEN_MINUS: value = value - _ParseProduct(); break; default: fTokenizer.RewindToken(); return value; } } }