/* This file is part of solidity. solidity is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. solidity is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with solidity. If not, see . */ // SPDX-License-Identifier: GPL-3.0 /** * Yul interpreter. */ #include #include #include using namespace solidity; using namespace solidity::yul; using namespace solidity::yul::test; using namespace std; namespace { void printVariable(YulString const& _name, u256 const& _value) { cout << "\t" << _name.str() << " = " << _value.str(); if (_value != 0) cout << " (" << toCompactHexWithPrefix(_value) << ")"; cout << endl; } } void InspectedInterpreter::run( std::shared_ptr _inspector, InterpreterState& _state, Dialect const& _dialect, Block const& _ast, bool _disableExternalCalls, bool _disableMemoryTrace ) { Scope scope; InspectedInterpreter{_inspector, _state, _dialect, scope, _disableExternalCalls, _disableMemoryTrace}(_ast); } Inspector::NodeAction Inspector::queryUser(DebugData const& _data, map const& _variables) { if (m_stepMode == NodeAction::RunNode) { // Output instructions that are being skipped/run cout << "Running " << currentSource(_data) << endl; return NodeAction::StepThroughNode; } string input; while (true) { // Output sourcecode about to run. cout << "> " << currentSource(_data) << endl; // Ask user for action cout << endl << "(s)tep/(n)ext/(i)nspect/(p)rint/all (v)ariables?" << endl << "# "; cout.flush(); getline(cin, input); boost::algorithm::trim(input); // Imitate GDB and repeat last cmd for empty string input. if (input == "") input = m_lastInput; else m_lastInput = input; if (input == "next" || input == "n") return NodeAction::RunNode; else if (input == "step" || input == "s") return NodeAction::StepThroughNode; else if (input == "inspect" || input == "i") m_state.dumpTraceAndState(cout, false); else if (input == "variables" || input == "v") { for (auto &&[yulStr, val]: _variables) printVariable(yulStr, val); cout << endl; } else if ( boost::starts_with(input, "print") || boost::starts_with(input, "p") ) { size_t whitespacePos = input.find(' '); if (whitespacePos == string::npos) cout << "Error parsing command! Expected variable name." << endl; string const varname = input.substr(whitespacePos + 1); vector candidates; bool found = false; for (auto &&[yulStr, val]: _variables) if (yulStr.str() == varname) { printVariable(yulStr, val); found = true; break; } if (!found) cout << varname << " not found." << endl; } } } std::string Inspector::currentSource(DebugData const& _data) const { return m_source.substr( static_cast(_data.nativeLocation.start), static_cast(_data.nativeLocation.end - _data.nativeLocation.start) ); } u256 InspectedInterpreter::evaluate(Expression const& _expression) { InspectedExpressionEvaluator ev(m_inspector, m_state, m_dialect, *m_scope, m_variables, m_disableExternalCalls, m_disableMemoryTrace); ev.visit(_expression); return ev.value(); } std::vector InspectedInterpreter::evaluateMulti(Expression const& _expression) { InspectedExpressionEvaluator ev(m_inspector, m_state, m_dialect, *m_scope, m_variables, m_disableExternalCalls, m_disableMemoryTrace); ev.visit(_expression); return ev.values(); }