/* This file is part of cpp-ethereum. cpp-ethereum 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. cpp-ethereum 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 cpp-ethereum. If not, see . */ /** @file DebuggingStateWrapper.cpp * @author Yann yann@ethdev.com * @date 2014 * Used to translate c++ type (u256, bytes, ...) into friendly value (to be used by QML). */ #include #include #include #include #include #include #include #include #include #include #include "DebuggingStateWrapper.h" #include "QBigInt.h" using namespace dev; using namespace dev::eth; using namespace dev::mix; namespace { static QVariantList memDumpToList(bytes const& _bytes, unsigned _width, bool _includeAddress = false) { QVariantList dumpList; for (unsigned i = 0; i < _bytes.size(); i += _width) { std::stringstream ret; if (_includeAddress) { ret << std::setfill('0') << std::setw(6) << std::hex << i << " "; ret << " "; } for (unsigned j = i; j < i + _width; ++j) if (j < _bytes.size()) if (_bytes[j] >= 32 && _bytes[j] < 127) ret << (char)_bytes[j]; else ret << '?'; else ret << ' '; QString strPart = QString::fromStdString(ret.str()); ret.clear(); ret.str(std::string()); for (unsigned j = i; j < i + _width && j < _bytes.size(); ++j) ret << std::setfill('0') << std::setw(2) << std::hex << (unsigned)_bytes[j] << " "; QString hexPart = QString::fromStdString(ret.str()); QStringList line = { strPart, hexPart }; dumpList.push_back(line); } return dumpList; } } QCode* QMachineState::getHumanReadableCode(QObject* _owner, const Address& _address, const bytes& _code, QHash& o_codeMap) { QVariantList codeStr; for (unsigned i = 0; i <= _code.size(); ++i) { byte b = i < _code.size() ? _code[i] : 0; try { QString s = QString::fromStdString(instructionInfo((Instruction)b).name); std::ostringstream out; out << std::hex << std::setw(4) << std::setfill('0') << i; int offset = i; if (b >= (byte)Instruction::PUSH1 && b <= (byte)Instruction::PUSH32) { unsigned bc = getPushNumber((Instruction)b); s = "PUSH 0x" + QString::fromStdString(toHex(bytesConstRef(&_code[i + 1], bc))); i += bc; } o_codeMap[offset] = codeStr.size(); codeStr.append(QVariant::fromValue(new QInstruction(_owner, QString::fromStdString(out.str()) + " " + s))); } catch (...) { qDebug() << QString("Unhandled exception!") << endl << QString::fromStdString(boost::current_exception_diagnostic_information()); break; // probably hit data segment } } return new QCode(_owner, QString::fromStdString(toString(_address)), std::move(codeStr)); } QBigInt* QMachineState::gasCost() { return new QBigInt(m_state.gasCost); } QBigInt* QMachineState::gas() { return new QBigInt(m_state.gas); } QBigInt* QMachineState::newMemSize() { return new QBigInt(m_state.newMemSize); } QStringList QMachineState::debugStack() { QStringList stack; for (std::vector::reverse_iterator i = m_state.stack.rbegin(); i != m_state.stack.rend(); ++i) stack.append(QString::fromStdString(prettyU256(*i))); return stack; } QStringList QMachineState::debugStorage() { QStringList storage; for (auto const& i: m_state.storage) { std::stringstream s; s << "@" << prettyU256(i.first) << "\t" << prettyU256(i.second); storage.append(QString::fromStdString(s.str())); } return storage; } QVariantList QMachineState::debugMemory() { return memDumpToList(m_state.memory, 16, true); } QCallData* QMachineState::getDebugCallData(QObject* _owner, bytes const& _data) { return new QCallData(_owner, memDumpToList(_data, 16)); } QVariantList QMachineState::levels() { QVariantList levelList; for (unsigned l: m_state.levels) levelList.push_back(l); return levelList; } QString QMachineState::instruction() { return QString::fromStdString(dev::eth::instructionInfo(m_state.inst).name); } QString QMachineState::endOfDebug() { if (m_state.gasCost > m_state.gas) return QObject::tr("OUT-OF-GAS"); else if (m_state.inst == Instruction::RETURN && m_state.stack.size() >= 2) { unsigned from = (unsigned)m_state.stack.back(); unsigned size = (unsigned)m_state.stack[m_state.stack.size() - 2]; unsigned o = 0; bytes out(size, 0); for (; o < size && from + o < m_state.memory.size(); ++o) out[o] = m_state.memory[from + o]; return QObject::tr("RETURN") + " " + QString::fromStdString(dev::memDump(out, 16, false)); } else if (m_state.inst == Instruction::STOP) return QObject::tr("STOP"); else if (m_state.inst == Instruction::SUICIDE && m_state.stack.size() >= 1) return QObject::tr("SUICIDE") + " 0x" + QString::fromStdString(toString(right160(m_state.stack.back()))); else return QObject::tr("EXCEPTION"); }