Browse Source

debugging into calls

cl-refactor
arkpar 10 years ago
parent
commit
c820b2597e
  1. 7
      mix/AssemblyDebuggerControl.cpp
  2. 4
      mix/AssemblyDebuggerControl.h
  3. 40
      mix/ClientModel.cpp
  4. 10
      mix/ClientModel.h
  5. 2
      mix/CodeModel.cpp
  6. 54
      mix/DebuggingStateWrapper.cpp
  7. 84
      mix/DebuggingStateWrapper.h
  8. 48
      mix/MixClient.cpp
  9. 9
      mix/MixClient.h
  10. 14
      mix/qml/Debugger.qml
  11. 110
      mix/qml/js/Debugger.js

7
mix/AssemblyDebuggerControl.cpp

@ -29,7 +29,6 @@ using namespace dev::mix;
AssemblyDebuggerControl::AssemblyDebuggerControl(AppContext* _context):
Extension(_context, ExtensionDisplayBehavior::RightView)
{
connect(_context->clientModel(), &ClientModel::showDebuggerWindow, this, &AssemblyDebuggerControl::showDebugger, Qt::QueuedConnection);
}
QString AssemblyDebuggerControl::contentUrl() const
@ -45,9 +44,3 @@ QString AssemblyDebuggerControl::title() const
void AssemblyDebuggerControl::start() const
{
}
void AssemblyDebuggerControl::showDebugger()
{
QObject* debugPanel = m_view->findChild<QObject*>("debugPanel", Qt::FindChildrenRecursively);
QMetaObject::invokeMethod(debugPanel, "update", Q_ARG(QVariant, true));
}

4
mix/AssemblyDebuggerControl.h

@ -42,10 +42,6 @@ public:
void start() const override;
QString title() const override;
QString contentUrl() const override;
private slots:
/// Update UI with machine states result. Displayed in the right side tab.
void showDebugger();
};
}

40
mix/ClientModel.cpp

@ -72,7 +72,10 @@ ClientModel::ClientModel(AppContext* _context):
qRegisterMetaType<QList<QVariableDefinition*>>("QList<QVariableDefinition*>");
qRegisterMetaType<QList<QVariableDeclaration*>>("QList<QVariableDeclaration*>");
qRegisterMetaType<QVariableDeclaration*>("QVariableDeclaration*");
qRegisterMetaType<AssemblyDebuggerData>("AssemblyDebuggerData");
qRegisterMetaType<QMachineState*>("QMachineState");
qRegisterMetaType<QInstruction*>("QInstruction");
qRegisterMetaType<QCode*>("QCode");
qRegisterMetaType<QCallData*>("QCallData");
qRegisterMetaType<TransactionLogEntry*>("TransactionLogEntry");
connect(this, &ClientModel::runComplete, this, &ClientModel::showDebugger, Qt::QueuedConnection);
@ -251,24 +254,27 @@ void ClientModel::showDebugger()
void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t)
{
//we need to wrap states in a QObject before sending to QML.
QList<QObject*> wStates;
for (unsigned i = 0; i < _t.machineStates.size(); i++)
{
QPointer<DebuggingStateWrapper> s(new DebuggingStateWrapper(_t.executionCode, _t.executionData.toBytes()));
s->setState(_t.machineStates[i]);
wStates.append(s);
}
QDebugData* debugData = new QDebugData();
QQmlEngine::setObjectOwnership(debugData, QQmlEngine::JavaScriptOwnership);
QList<QCode*> codes;
for (bytes const& code: _t.executionCode)
codes.push_back(QMachineState::getHumanReadableCode(debugData, code));
QList<QCallData*> data;
for (bytes const& d: _t.transactionData)
data.push_back(QMachineState::getDebugCallData(debugData, d));
QVariantList states;
for (MachineState const& s: _t.machineStates)
states.append(QVariant::fromValue(new QMachineState(debugData, s, codes[s.codeIndex], data[s.dataIndex])));
debugData->setStates(std::move(states));
QList<QVariableDefinition*> returnParameters;
//QList<QVariableDefinition*> returnParameters;
//returnParameters = encoder.decode(f->returnParameters(), debuggingContent.returnValue);
//collect states for last transaction
AssemblyDebuggerData code = DebuggingStateWrapper::getHumanReadableCode(_t.executionCode);
m_context->appEngine()->rootContext()->setContextProperty("debugStates", QVariant::fromValue(wStates));
m_context->appEngine()->rootContext()->setContextProperty("humanReadableExecutionCode", QVariant::fromValue(std::get<0>(code)));
m_context->appEngine()->rootContext()->setContextProperty("bytesCodeMapping", QVariant::fromValue(std::get<1>(code)));
m_context->appEngine()->rootContext()->setContextProperty("contractCallReturnParameters", QVariant::fromValue(new QVariableDefinitionList(returnParameters)));
showDebuggerWindow();
debugDataReady(debugData);
}
@ -339,9 +345,9 @@ void ClientModel::onNewTransaction()
else
{
//call
if (tr.transactionData.size() >= 4)
if (tr.transactionData.size() > 0 && tr.transactionData.front().size() >= 4)
{
functionHash = FixedHash<4>(tr.transactionData.data(), FixedHash<4>::ConstructFromPointer);
functionHash = FixedHash<4>(tr.transactionData.front().data(), FixedHash<4>::ConstructFromPointer);
function = QString::fromStdString(toJS(functionHash));
call = true;
}

10
mix/ClientModel.h

@ -25,14 +25,9 @@
#include <atomic>
#include <map>
#include "DebuggingStateWrapper.h"
#include <QString>
#include "MixClient.h"
using AssemblyDebuggerData = std::tuple<QList<QObject*>, dev::mix::QQMLMap*>;
Q_DECLARE_METATYPE(AssemblyDebuggerData)
Q_DECLARE_METATYPE(dev::mix::ExecutionResult)
namespace dev
{
namespace mix
@ -42,6 +37,7 @@ class AppContext;
class Web3Server;
class RpcConnector;
class QEther;
class QDebugData;
/// Backend transaction config class
struct TransactionSettings
@ -156,7 +152,7 @@ signals:
/// Execution state changed
void runStateChanged();
/// Show debugger window request
void showDebuggerWindow();
void debugDataReady(QObject* _debugData);
/// ethereum.js RPC response ready
/// @param _message RPC response in Json format
void apiResponse(QString const& _message);

2
mix/CodeModel.cpp

@ -133,7 +133,7 @@ void CodeModel::runCompilationJob(int _jobId, QString const& _code)
if (_jobId != m_backgroundJobId)
return; //obsolete job
solidity::CompilerStack cs;
solidity::CompilerStack cs(true);
std::unique_ptr<CompilationResult> result;
std::string source = _code.toStdString();

54
mix/DebuggingStateWrapper.cpp

@ -24,6 +24,7 @@
#include <QDebug>
#include <QPointer>
#include <QQmlEngine>
#include <QVariantList>
#include <libevmcore/Instruction.h>
#include <libdevcore/CommonJS.h>
#include <libdevcrypto/Common.h>
@ -35,10 +36,9 @@ using namespace dev;
using namespace dev::eth;
using namespace dev::mix;
std::tuple<QList<QObject*>, QQMLMap*> DebuggingStateWrapper::getHumanReadableCode(const bytes& _code)
QCode* QMachineState::getHumanReadableCode(QObject* _owner, const bytes& _code)
{
QList<QObject*> codeStr;
QMap<int, int> codeMapping;
QVariantList codeStr;
for (unsigned i = 0; i <= _code.size(); ++i)
{
byte b = i < _code.size() ? _code[i] : 0;
@ -47,7 +47,6 @@ std::tuple<QList<QObject*>, QQMLMap*> DebuggingStateWrapper::getHumanReadableCod
QString s = QString::fromStdString(instructionInfo((Instruction)b).name);
std::ostringstream out;
out << std::hex << std::setw(4) << std::setfill('0') << i;
codeMapping[i] = codeStr.size();
int line = i;
if (b >= (byte)Instruction::PUSH1 && b <= (byte)Instruction::PUSH32)
{
@ -55,8 +54,7 @@ std::tuple<QList<QObject*>, QQMLMap*> DebuggingStateWrapper::getHumanReadableCod
s = "PUSH 0x" + QString::fromStdString(toHex(bytesConstRef(&_code[i + 1], bc)));
i += bc;
}
QPointer<HumanReadableCode> humanCode(new HumanReadableCode(QString::fromStdString(out.str()) + " " + s, line));
codeStr.append(humanCode);
codeStr.append(QVariant::fromValue(new QInstruction(_owner, QString::fromStdString(out.str()) + " " + s, line)));
}
catch (...)
{
@ -65,25 +63,25 @@ std::tuple<QList<QObject*>, QQMLMap*> DebuggingStateWrapper::getHumanReadableCod
break; // probably hit data segment
}
}
return std::make_tuple(codeStr, QPointer<QQMLMap>(new QQMLMap(codeMapping)));
return new QCode(_owner, std::move(codeStr));
}
QBigInt* DebuggingStateWrapper::gasCost()
QBigInt* QMachineState::gasCost()
{
return new QBigInt(m_state.gasCost);
}
QBigInt* DebuggingStateWrapper::gas()
QBigInt* QMachineState::gas()
{
return new QBigInt(m_state.gas);
}
QBigInt* DebuggingStateWrapper::newMemSize()
QBigInt* QMachineState::newMemSize()
{
return new QBigInt(m_state.newMemSize);
}
QStringList DebuggingStateWrapper::debugStack()
QStringList QMachineState::debugStack()
{
QStringList stack;
for (std::vector<u256>::reverse_iterator i = m_state.stack.rbegin(); i != m_state.stack.rend(); ++i)
@ -91,7 +89,7 @@ QStringList DebuggingStateWrapper::debugStack()
return fillList(stack, "");
}
QStringList DebuggingStateWrapper::debugStorage()
QStringList QMachineState::debugStorage()
{
QStringList storage;
for (auto const& i: m_state.storage)
@ -103,7 +101,7 @@ QStringList DebuggingStateWrapper::debugStorage()
return fillList(storage, "@ -");
}
QVariantList DebuggingStateWrapper::debugMemory()
QVariantList QMachineState::debugMemory()
{
std::vector<std::vector<std::string>> dump = memDumpToList(m_state.memory, 16);
QStringList filled;
@ -113,17 +111,17 @@ QVariantList DebuggingStateWrapper::debugMemory()
return fillList(qVariantDump(dump), QVariant(filled));
}
QVariantList DebuggingStateWrapper::debugCallData()
QCallData* QMachineState::getDebugCallData(QObject* _owner, bytes const& _data)
{
std::vector<std::vector<std::string>> dump = memDumpToList(m_data, 16);
std::vector<std::vector<std::string>> dump = memDumpToList(_data, 16);
QStringList filled;
filled.append(" ");
filled.append(" ");
filled.append(" ");
return fillList(qVariantDump(dump), QVariant(filled));
return new QCallData(_owner, fillList(qVariantDump(dump), QVariant(filled)));
}
std::vector<std::vector<std::string>> DebuggingStateWrapper::memDumpToList(bytes const& _bytes, unsigned _width)
std::vector<std::vector<std::string>> QMachineState::memDumpToList(bytes const& _bytes, unsigned _width)
{
std::vector<std::vector<std::string>> dump;
for (unsigned i = 0; i < _bytes.size(); i += _width)
@ -155,7 +153,7 @@ std::vector<std::vector<std::string>> DebuggingStateWrapper::memDumpToList(bytes
return dump;
}
QVariantList DebuggingStateWrapper::qVariantDump(std::vector<std::vector<std::string>> const& _dump)
QVariantList QMachineState::qVariantDump(std::vector<std::vector<std::string>> const& _dump)
{
QVariantList ret;
for (std::vector<std::string> const& line: _dump)
@ -168,7 +166,7 @@ QVariantList DebuggingStateWrapper::qVariantDump(std::vector<std::vector<std::st
return ret;
}
QStringList DebuggingStateWrapper::fillList(QStringList& _list, QString const& _emptyValue)
QStringList QMachineState::fillList(QStringList& _list, QString const& _emptyValue)
{
if (_list.size() < 20)
{
@ -178,7 +176,7 @@ QStringList DebuggingStateWrapper::fillList(QStringList& _list, QString const& _
return _list;
}
QVariantList DebuggingStateWrapper::fillList(QVariantList _list, QVariant const& _emptyValue)
QVariantList QMachineState::fillList(QVariantList _list, QVariant const& _emptyValue)
{
if (_list.size() < 20)
{
@ -188,14 +186,13 @@ QVariantList DebuggingStateWrapper::fillList(QVariantList _list, QVariant const&
return _list;
}
QStringList DebuggingStateWrapper::levels()
QStringList QMachineState::levels()
{
QStringList levelsStr;
for (unsigned i = 0; i <= m_state.levels.size(); ++i)
{
std::ostringstream out;
out << m_state.cur.abridged();
out << m_state.address.abridged();
if (i)
out << " " << instructionInfo(m_state.inst).name << " @0x" << std::hex << m_state.curPC;
levelsStr.append(QString::fromStdString(out.str()));
@ -203,19 +200,12 @@ QStringList DebuggingStateWrapper::levels()
return levelsStr;
}
QString DebuggingStateWrapper::headerInfo()
{
std::ostringstream ss;
ss << std::dec << " " << QApplication::tr("STEP").toStdString() << " : " << m_state.steps << " | PC: 0x" << std::hex << m_state.curPC << " : " << dev::eth::instructionInfo(m_state.inst).name << " | ADDMEM: " << std::dec << m_state.newMemSize << " " << QApplication::tr("words").toStdString() << " | " << QApplication::tr("COST").toStdString() << " : " << std::dec << m_state.gasCost << " | " << QApplication::tr("GAS").toStdString() << " : " << std::dec << m_state.gas;
return QString::fromStdString(ss.str());
}
QString DebuggingStateWrapper::instruction()
QString QMachineState::instruction()
{
return QString::fromStdString(dev::eth::instructionInfo(m_state.inst).name);
}
QString DebuggingStateWrapper::endOfDebug()
QString QMachineState::endOfDebug()
{
if (m_state.gasCost > m_state.gas)
return QApplication::tr("OUT-OF-GAS");

84
mix/DebuggingStateWrapper.h

@ -39,45 +39,61 @@ namespace mix
/**
* @brief Contains the line nb of the assembly code and the corresponding index in the code bytes array.
*/
class HumanReadableCode: public QObject
class QInstruction: public QObject
{
Q_OBJECT
Q_PROPERTY(QString line READ line CONSTANT)
Q_PROPERTY(int processIndex READ processIndex CONSTANT)
Q_PROPERTY(QString line MEMBER m_line CONSTANT)
Q_PROPERTY(int processIndex MEMBER m_processIndex CONSTANT)
public:
HumanReadableCode(QString _line, int _processIndex): QObject(), m_line(_line), m_processIndex(_processIndex) {}
/// Get the assembly code line.
QString line() { return m_line; }
/// Get corresponding index.
int processIndex() { return m_processIndex; }
QInstruction(QObject* _owner, QString _line, int _processIndex): QObject(_owner), m_line(_line), m_processIndex(_processIndex) {}
private:
QString m_line;
int m_processIndex;
};
class QCode: public QObject
{
Q_OBJECT
Q_PROPERTY(QVariantList instructions MEMBER m_instructions CONSTANT)
/**
* @brief Publish QMap type to QML.
*/
class QQMLMap: public QObject
public:
QCode(QObject* _owner, QVariantList&& _instrunctions): QObject(_owner), m_instructions(_instrunctions) {}
private:
QVariantList m_instructions;
};
class QCallData: public QObject
{
Q_OBJECT
Q_PROPERTY(QVariantList items MEMBER m_items CONSTANT)
public:
QQMLMap(QMap<int, int> _map): QObject(), m_map(_map) { }
/// Get the value associated with _key store in n_map.
Q_INVOKABLE int getValue(int _key) { return m_map.value(_key); }
QCallData(QObject* _owner, QVariantList&& _items): QObject(_owner), m_items(_items) {}
private:
QMap<int, int> m_map;
QVariantList m_items;
};
class QDebugData: public QObject
{
Q_OBJECT
Q_PROPERTY(QVariantList states MEMBER m_states CONSTANT)
public:
QDebugData() { }
void setStates(QVariantList&& _states) { m_states = _states; }
private:
QVariantList m_states;
};
/**
* @brief Wrap DebuggingState in QObject
*/
class DebuggingStateWrapper: public QObject
class QMachineState: public QObject
{
Q_OBJECT
Q_PROPERTY(int step READ step CONSTANT)
@ -88,18 +104,25 @@ class DebuggingStateWrapper: public QObject
Q_PROPERTY(QStringList debugStack READ debugStack CONSTANT)
Q_PROPERTY(QStringList debugStorage READ debugStorage CONSTANT)
Q_PROPERTY(QVariantList debugMemory READ debugMemory CONSTANT)
Q_PROPERTY(QVariantList debugCallData READ debugCallData CONSTANT)
Q_PROPERTY(QString headerInfo READ headerInfo CONSTANT)
Q_PROPERTY(QObject* code MEMBER m_code CONSTANT)
Q_PROPERTY(QObject* callData MEMBER m_callData CONSTANT)
Q_PROPERTY(QString endOfDebug READ endOfDebug CONSTANT)
Q_PROPERTY(QBigInt* newMemSize READ newMemSize CONSTANT)
Q_PROPERTY(QStringList levels READ levels CONSTANT)
Q_PROPERTY(unsigned codeIndex READ codeIndex CONSTANT)
Q_PROPERTY(unsigned dataIndex READ dataIndex CONSTANT)
public:
DebuggingStateWrapper(bytes _code, bytes _data): QObject(), m_code(_code), m_data(_data) {}
QMachineState(QObject* _owner, MachineState const& _state, QCode* _code, QCallData* _callData):
QObject(_owner), m_state(_state), m_code(_code), m_callData(_callData) {}
/// Get the step of this machine states.
int step() { return (int)m_state.steps; }
/// Get the proccessed code index.
int curPC() { return (int)m_state.curPC; }
/// Get the code id
unsigned codeIndex() { return m_state.codeIndex; }
/// Get the call data id
unsigned dataIndex() { return m_state.dataIndex; }
/// Get gas cost.
QBigInt* gasCost();
/// Get gas used.
@ -111,8 +134,6 @@ public:
/// Get memory.
QVariantList debugMemory();
/// Get call data.
QVariantList debugCallData();
/// Get info to be displayed in the header.
QString headerInfo();
/// get end of debug information.
QString endOfDebug();
@ -126,20 +147,21 @@ public:
MachineState state() { return m_state; }
/// Set the current processed machine state.
void setState(MachineState _state) { m_state = _state; }
/// Convert all machine state in human readable code.
static std::tuple<QList<QObject*>, QQMLMap*> getHumanReadableCode(bytes const& _code);
/// Convert all machine states in human readable code.
static QCode* getHumanReadableCode(QObject* _owner, bytes const& _code);
/// Convert call data into human readable form
static QCallData* getDebugCallData(QObject* _owner, bytes const& _data);
private:
MachineState m_state;
bytes m_code;
bytes m_data;
QStringList fillList(QStringList& _list, QString const& _emptyValue);
QVariantList fillList(QVariantList _list, QVariant const& _emptyValue);
QVariantList qVariantDump(std::vector<std::vector<std::string>> const& _dump);
QCode* m_code;
QCallData* m_callData;
static QStringList fillList(QStringList& _list, QString const& _emptyValue);
static QVariantList fillList(QVariantList _list, QVariant const& _emptyValue);
static QVariantList qVariantDump(std::vector<std::vector<std::string>> const& _dump);
/// Nicely renders the given bytes to a string, store the content in an array.
/// @a _bytes: bytes array to be rendered as string. @a _width of a bytes line.
std::vector<std::vector<std::string>> memDumpToList(bytes const& _bytes, unsigned _width);
static std::vector<std::vector<std::string>> memDumpToList(bytes const& _bytes, unsigned _width);
};
}

48
mix/MixClient.cpp

@ -63,21 +63,46 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state)
bytes rlp = _t.rlp();
Executive execution(_state, LastHashes(), 0);
execution.setup(&rlp);
bytes code;
bytesConstRef data;
bool firstIteration = true;
std::vector<MachineState> machineStates;
std::vector<MachineState const*> levels;
std::vector<bytes> codes;
std::map<bytes const*, unsigned> codeIndexes;
std::vector<bytes> data;
std::map<bytesConstRef const*, unsigned> dataIndexes;
bytes const* lastCode = nullptr;
bytesConstRef const* lastData = nullptr;
unsigned codeIndex = 0;
unsigned dataIndex = 0;
auto onOp = [&](uint64_t steps, Instruction inst, dev::bigint newMemSize, dev::bigint gasCost, void* voidVM, void const* voidExt)
{
VM& vm = *(VM*)voidVM;
ExtVM const& ext = *(ExtVM const*)voidExt;
if (lastCode == nullptr || lastCode != &ext.code)
{
auto const& iter = codeIndexes.find(&ext.code);
if (iter != codeIndexes.end())
codeIndex = iter->second;
else
{
codeIndex = codes.size();
codes.push_back(ext.code);
codeIndexes[&ext.code] = codeIndex;
}
lastCode = &ext.code;
}
if (firstIteration)
if (lastData == nullptr || lastData != &ext.data)
{
code = ext.code;
data = ext.data;
firstIteration = false;
auto const& iter = dataIndexes.find(&ext.data);
if (iter != dataIndexes.end())
dataIndex = iter->second;
else
{
dataIndex = data.size();
data.push_back(ext.data.toBytes());
dataIndexes[&ext.data] = dataIndex;
}
lastData = &ext.data;
}
if (levels.size() < ext.depth)
@ -85,8 +110,8 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state)
else
levels.resize(ext.depth);
machineStates.push_back(MachineState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, vm.gas(),
vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels}));
machineStates.emplace_back(MachineState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, vm.gas(),
vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels, codeIndex, dataIndex}));
};
execution.go(onOp);
@ -95,9 +120,8 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state)
ExecutionResult d;
d.returnValue = execution.out().toVector();
d.machineStates = machineStates;
d.executionCode = code;
d.executionData = data;
d.transactionData = _t.data();
d.executionCode = std::move(codes);
d.transactionData = std::move(data);
d.address = _t.receiveAddress();
d.sender = _t.sender();
d.value = _t.value();

9
mix/MixClient.h

@ -38,7 +38,7 @@ namespace mix
struct MachineState
{
uint64_t steps;
dev::Address cur;
dev::Address address;
dev::u256 curPC;
dev::eth::Instruction inst;
dev::bigint newMemSize;
@ -48,6 +48,8 @@ struct MachineState
dev::bigint gasCost;
std::map<dev::u256, dev::u256> storage;
std::vector<MachineState const*> levels;
unsigned codeIndex;
unsigned dataIndex;
};
/**
@ -58,9 +60,8 @@ struct ExecutionResult
ExecutionResult(): receipt(dev::h256(), dev::h256(), dev::eth::LogEntries()) {}
std::vector<MachineState> machineStates;
bytes transactionData;
bytes executionCode;
bytesConstRef executionData;
std::vector<bytes> transactionData;
std::vector<bytes> executionCode;
bytes returnValue;
dev::Address address;
dev::Address sender;

14
mix/qml/Debugger.qml

@ -27,11 +27,11 @@ Rectangle {
forceActiveFocus();
}
function update(giveFocus)
function update(data, giveFocus)
{
if (statusPane.result.successful)
{
Debugger.init();
Debugger.init(data);
debugScrollArea.visible = true;
compilationErrorArea.visible = false;
machineStates.visible = true;
@ -50,9 +50,16 @@ Rectangle {
forceActiveFocus();
}
Connections {
target: clientModel
onDebugDataReady: {
update(_debugData, true);
}
}
Connections {
target: codeModel
onCompilationComplete: update(false)
onCompilationComplete: update(null, false);
}
Rectangle
@ -277,6 +284,7 @@ Rectangle {
delegate: renderDelegate
highlight: highlightBar
highlightFollowsCurrentItem: false
model: ListModel {}
}
Component {

110
mix/qml/js/Debugger.js

@ -1,35 +1,53 @@
//humanReadableExecutionCode => contain human readable code.
//debugStates => contain all debug states.
//bytesCodeMapping => mapping between humanReadableExecutionCode and bytesCode.
//debugData => contain all debug states.
//statesList => ListView
var currentSelectedState = null;
var jumpStartingPoint = null;
function init()
var debugData = null;
var codeMap = null;
function init(data)
{
if (typeof(debugStates) === "undefined")
jumpOutBackAction.enabled(false);
jumpIntoBackAction.enabled(false);
jumpIntoForwardAction.enabled(false);
jumpOutForwardAction.enabled(false);
if (data === null) {
statesList.model.clear();
statesSlider.maximumValue = 0;
statesSlider.value = 0;
currentSelectedState = null;
jumpStartingPoint = null;
debugData = null;
return;
}
statesSlider.maximumValue = debugStates.length - 1;
debugData = data;
statesSlider.maximumValue = data.states.length - 1;
statesSlider.value = 0;
statesList.model = humanReadableExecutionCode;
currentSelectedState = 0;
setupInstructions(currentSelectedState);
select(currentSelectedState);
}
jumpOutBackAction.enabled(false);
jumpIntoBackAction.enabled(false);
jumpIntoForwardAction.enabled(false);
jumpOutForwardAction.enabled(false);
function setupInstructions(stateIndex) {
var instructions = debugData.states[stateIndex].code.instructions;
codeMap = {};
statesList.model.clear();
for (var i = 0; i < instructions.length; i++) {
statesList.model.append(instructions[i]);
codeMap[instructions[i].processIndex] = i;
}
}
function moveSelection(incr)
{
if (typeof(debugStates) === "undefined")
return;
var prevState = currentSelectedState;
if (currentSelectedState + incr >= 0)
{
if (currentSelectedState + incr < debugStates.length)
if (currentSelectedState + incr < debugData.states.length)
select(currentSelectedState + incr);
statesSlider.value = currentSelectedState;
}
@ -37,16 +55,15 @@ function moveSelection(incr)
function select(stateIndex)
{
if (typeof(debugStates) === "undefined")
return;
if (debugData.states[stateIndex].codeIndex !== debugData.states[currentSelectedState].codeIndex)
setupInstructions(stateIndex);
currentSelectedState = stateIndex;
var codeLine = codeStr(stateIndex);
var state = debugStates[stateIndex];
var state = debugData.states[stateIndex];
highlightSelection(codeLine);
currentSelectedState = stateIndex;
completeCtxInformation(state);
if (state.instruction === "JUMP")
if (state.instruction === "CALL" || state.instruction === "CREATE")
jumpIntoForwardAction.enabled(true);
else
jumpIntoForwardAction.enabled(false);
@ -59,11 +76,8 @@ function select(stateIndex)
function codeStr(stateIndex)
{
if (typeof(debugStates) === "undefined")
return;
var state = debugStates[stateIndex];
return bytesCodeMapping.getValue(state.curPC);
var state = debugData.states[stateIndex];
return codeMap[state.curPC];
}
function highlightSelection(index)
@ -73,13 +87,10 @@ function highlightSelection(index)
function completeCtxInformation(state)
{
if (typeof(debugStates) === "undefined")
return;
currentStep.update(state.step);
mem.update(state.newMemSize.value() + " " + qsTr("words"));
stepCost.update(state.gasCost.value());
gasSpent.update(debugStates[0].gas.subtract(state.gas).value());
gasSpent.update(debugData.states[0].gas.subtract(state.gas).value());
stack.listModel = state.debugStack;
storage.listModel = state.debugStorage;
@ -87,17 +98,8 @@ function completeCtxInformation(state)
callDataDump.listModel = state.debugCallData;
}
function displayReturnValue()
{
headerReturnList.model = contractCallReturnParameters;
headerReturnList.update();
}
function stepOutBack()
{
if (typeof(debugStates) === "undefined")
return;
if (jumpStartingPoint != null)
{
select(jumpStartingPoint);
@ -114,15 +116,12 @@ function stepIntoBack()
function stepOverBack()
{
if (typeof(debugStates) === "undefined")
return;
var state = debugStates[currentSelectedState];
if (state.instruction === "JUMPDEST")
var state = debugData.states[currentSelectedState];
if (state.instruction === "CALL" || state.instruction === "CREATE")
{
for (var k = currentSelectedState; k > 0; k--)
{
var line = bytesCodeMapping.getValue(debugStates[k].curPC);
var line = codeMap[debugData.states[k].curPC];
if (line === statesList.currentIndex - 2)
{
select(k);
@ -136,15 +135,12 @@ function stepOverBack()
function stepOverForward()
{
if (typeof(debugStates) === "undefined")
return;
var state = debugStates[currentSelectedState];
if (state.instruction === "JUMP")
var state = debugData.states[currentSelectedState];
if (state.instruction === "CALL" || state.instruction === "CREATE")
{
for (var k = currentSelectedState; k < debugStates.length; k++)
for (var k = currentSelectedState; k < debugData.states.length; k++)
{
var line = bytesCodeMapping.getValue(debugStates[k].curPC);
var line = codeMap[debugData.states[k].curPC];
if (line === statesList.currentIndex + 2)
{
select(k);
@ -158,11 +154,8 @@ function stepOverForward()
function stepIntoForward()
{
if (typeof(debugStates) === "undefined")
return;
var state = debugStates[currentSelectedState];
if (state.instruction === "JUMP")
var state = debugData.states[currentSelectedState];
if (state.instruction === "CALL" || state.instruction === "CREATE")
{
jumpStartingPoint = currentSelectedState;
moveSelection(1);
@ -184,6 +177,5 @@ function stepOutForward()
function jumpTo(value)
{
currentSelectedState = value;
select(currentSelectedState);
select(value);
}

Loading…
Cancel
Save