From 938636fbbba73189db5b73b1a7e3b4471f36a2fe Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 16 Jul 2014 15:06:57 +0200 Subject: [PATCH] Debugger improvements. --- alethzero/Main.ui | 62 ++++++++++++++++++++++--- alethzero/MainWin.cpp | 102 +++++++++++++++++++++++++++++++++--------- alethzero/MainWin.h | 8 +++- 3 files changed, 142 insertions(+), 30 deletions(-) diff --git a/alethzero/Main.ui b/alethzero/Main.ui index a7f368f80..1f0a3b8df 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -161,16 +161,26 @@ Deb&ug + + + &Dump Trace + + + + - - + + + + + @@ -1527,15 +1537,15 @@ font-size: 14pt &Load Javascript... - + false - Step &Backwards + Step Over &Backwards - Shift+F10 + Ctrl+F10 @@ -1543,12 +1553,12 @@ font-size: 14pt &Clear Pending - + false - &Dump Standard Trace + Standard with &Storage... @@ -1573,6 +1583,44 @@ font-size: 14pt Shift+F11 + + + false + + + S&tandard... + + + + + false + + + Step Into Backwards + + + Ctrl+F11 + + + + + false + + + Step Out Backwards + + + Ctrl+Shift+F11 + + + + + false + + + Debu&g Current Transaction + + diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 92b3cb06e..cc843d14a 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -839,6 +839,7 @@ void Main::on_inject_triggered() void Main::on_blocks_currentItemChanged() { ui->info->clear(); + ui->debugCurrent->setEnabled(false); eth::ClientGuard g(m_client.get()); if (auto item = ui->blocks->currentItem()) { @@ -906,19 +907,39 @@ void Main::on_blocks_currentItemChanged() s << eth::memDump(tx.data, 16, true); } auto st = eth::State(m_client->state().db(), m_client->blockChain(), h); - s << renderDiff(st.pendingDiff(txi)); + eth::State before = st.fromPending(txi); + eth::State after = st.fromPending(txi + 1); + s << renderDiff(before.diff(after)); +// cerr << "State dump *********************************" << endl << after << "*********************************************" << endl; + ui->debugCurrent->setEnabled(true); + } + + + ui->info->appendHtml(QString::fromStdString(s.str())); + } +} + +void Main::on_debugCurrent_triggered() +{ + eth::ClientGuard g(m_client.get()); + if (auto item = ui->blocks->currentItem()) + { + auto hba = item->data(Qt::UserRole).toByteArray(); + assert(hba.size() == 32); + auto h = h256((byte const*)hba.data(), h256::ConstructFromPointer); + + if (!item->data(Qt::UserRole + 1).isNull()) + { + eth::State st(m_client->state().db(), m_client->blockChain(), h); + unsigned txi = item->data(Qt::UserRole + 1).toInt(); m_executiveState = st.fromPending(txi); m_currentExecution = unique_ptr(new Executive(m_executiveState)); Transaction t = st.pending()[txi]; auto r = t.rlp(); - populateDebugger(&r); m_currentExecution.reset(); } - - - ui->info->appendHtml(QString::fromStdString(s.str())); } } @@ -1304,9 +1325,9 @@ void Main::on_create_triggered() void Main::on_debugStep_triggered() { - if (ui->debugTimeline->value() < m_history.size() && (m_history[ui->debugTimeline->value()].inst == Instruction::CALL || m_history[ui->debugTimeline->value()].inst == Instruction::CREATE)) + auto l = m_history[ui->debugTimeline->value()].levels.size(); + if (ui->debugTimeline->value() < m_history.size() && m_history[ui->debugTimeline->value() + 1].levels.size() > l) { - auto l = m_history[ui->debugTimeline->value()].levels.size(); on_debugStepInto_triggered(); if (m_history[ui->debugTimeline->value()].levels.size() > l) on_debugStepOut_triggered(); @@ -1333,23 +1354,57 @@ void Main::on_debugStepOut_triggered() } } -void Main::on_debugStepback_triggered() +void Main::on_debugStepBackInto_triggered() { ui->debugTimeline->setValue(ui->debugTimeline->value() - 1); ui->callStack->setCurrentRow(0); } +void Main::on_debugStepBack_triggered() +{ + auto l = m_history[ui->debugTimeline->value()].levels.size(); + if (ui->debugTimeline->value() > 0 && m_history[ui->debugTimeline->value() - 1].levels.size() > l) + { + on_debugStepBackInto_triggered(); + if (m_history[ui->debugTimeline->value()].levels.size() > l) + on_debugStepBackOut_triggered(); + } + else + on_debugStepBackInto_triggered(); +} + +void Main::on_debugStepBackOut_triggered() +{ + if (ui->debugTimeline->value() > 0) + { + auto ls = m_history[ui->debugTimeline->value()].levels.size(); + int l = ui->debugTimeline->value(); + for (; l > 0 && m_history[l].levels.size() >= ls; --l) {} + ui->debugTimeline->setValue(l); + ui->callStack->setCurrentRow(0); + } +} + void Main::on_dumpTrace_triggered() +{ + QString fn = QFileDialog::getSaveFileName(this, "Select file to output EVM trace"); + ofstream f(fn.toStdString()); + if (f.is_open()) + for (WorldState const& ws: m_history) + f << ws.cur << " " << hex << toHex(eth::toCompactBigEndian(ws.curPC, 1)) << " " << hex << toHex(eth::toCompactBigEndian((int)(byte)ws.inst, 1)) << " " << hex << toHex(eth::toCompactBigEndian((uint64_t)ws.gas, 1)) << endl; +} + +void Main::on_dumpTraceStorage_triggered() { QString fn = QFileDialog::getSaveFileName(this, "Select file to output EVM trace"); ofstream f(fn.toStdString()); if (f.is_open()) for (WorldState const& ws: m_history) { -/* if (ws.inst == Instruction::STOP || ws.inst == Instruction::RETURN || ws.inst == Instruction::SUICIDE) + if (ws.inst == Instruction::STOP || ws.inst == Instruction::RETURN || ws.inst == Instruction::SUICIDE) for (auto i: ws.storage) f << toHex(eth::toCompactBigEndian(i.first, 1)) << " " << toHex(eth::toCompactBigEndian(i.second, 1)) << endl; -*/ f << ws.cur << " " << hex << toHex(eth::toCompactBigEndian(ws.curPC, 1)) << " " << hex << toHex(eth::toCompactBigEndian((int)(byte)ws.inst, 1)) << " " << hex << toHex(eth::toCompactBigEndian((uint64_t)ws.gas, 1)) << endl; + f << ws.cur << " " << hex << toHex(eth::toCompactBigEndian(ws.curPC, 1)) << " " << hex << toHex(eth::toCompactBigEndian((int)(byte)ws.inst, 1)) << " " << hex << toHex(eth::toCompactBigEndian((uint64_t)ws.gas, 1)) << endl; } } @@ -1358,6 +1413,19 @@ void Main::on_callStack_currentItemChanged() updateDebugger(); } +void Main::alterDebugStateGroup(bool _enable) const +{ + ui->debugStep->setEnabled(_enable); + ui->debugStepInto->setEnabled(_enable); + ui->debugStepOut->setEnabled(_enable); + ui->debugStepBackInto->setEnabled(_enable); + ui->debugStepBackOut->setEnabled(_enable); + ui->dumpTrace->setEnabled(_enable); + ui->dumpTraceStorage->setEnabled(_enable); + ui->debugStepBack->setEnabled(_enable); + ui->debugPanel->setEnabled(_enable); +} + void Main::debugFinished() { m_codes.clear(); @@ -1371,13 +1439,8 @@ void Main::debugFinished() ui->debugMemory->setHtml(""); ui->debugStorage->setHtml(""); ui->debugStateInfo->setText(""); + alterDebugStateGroup(false); // ui->send->setEnabled(true); - ui->debugStep->setEnabled(false); - ui->debugStepInto->setEnabled(false); - ui->debugStepOut->setEnabled(false); - ui->dumpTrace->setEnabled(false); - ui->debugStepback->setEnabled(false); - ui->debugPanel->setEnabled(false); } void Main::initDebugger() @@ -1385,12 +1448,7 @@ void Main::initDebugger() // ui->send->setEnabled(false); if (m_history.size()) { - ui->debugStep->setEnabled(true); - ui->dumpTrace->setEnabled(true); - ui->debugStepInto->setEnabled(true); - ui->debugStepOut->setEnabled(true); - ui->debugStepback->setEnabled(true); - ui->debugPanel->setEnabled(true); + alterDebugStateGroup(true); ui->debugCode->setEnabled(false); ui->debugTimeline->setMinimum(0); ui->debugTimeline->setMaximum(m_history.size()); diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index b2bda680a..9f5cb3d7a 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -110,7 +110,7 @@ private slots: void on_quit_triggered() { close(); } void on_urlEdit_returnPressed(); void on_debugStep_triggered(); - void on_debugStepback_triggered(); + void on_debugStepBack_triggered(); void on_debug_clicked(); void on_debugTimeline_valueChanged(); void on_jsInput_returnPressed(); @@ -124,9 +124,13 @@ private slots: void on_blockChainFilter_textChanged(); void on_clearPending_triggered(); void on_dumpTrace_triggered(); + void on_dumpTraceStorage_triggered(); void on_debugStepInto_triggered(); void on_debugStepOut_triggered(); + void on_debugStepBackOut_triggered(); + void on_debugStepBackInto_triggered(); void on_callStack_currentItemChanged(); + void on_debugCurrent_triggered(); void refresh(bool _override = false); void refreshNetwork(); @@ -150,6 +154,8 @@ private: eth::Address fromString(QString const& _a) const; std::string renderDiff(eth::StateDiff const& _d) const; + void alterDebugStateGroup(bool _enable) const; + eth::State const& state() const; void updateFee();