From c565cb3affea5fe03da437e93b3574edf736894b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 9 Jul 2014 20:41:00 +0100 Subject: [PATCH] Debugger improvements. --- alethzero/Main.ui | 12 ++++- alethzero/MainWin.cpp | 100 +++++++++++++++++++++++++++++------------- alethzero/MainWin.h | 4 +- 3 files changed, 82 insertions(+), 34 deletions(-) diff --git a/alethzero/Main.ui b/alethzero/Main.ui index 532333deb..f2d44b040 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -1010,7 +1010,7 @@ true - Qt::NoTextInteraction + Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse @@ -1024,7 +1024,15 @@ true - Qt::NoTextInteraction + Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + QFrame::NoFrame + + + true diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index c3dffaa39..b7f7e626d 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -284,8 +285,16 @@ QString fromRaw(eth::h256 _n) if (_n) { std::string s((char const*)_n.data(), 32); - if (s.find_first_of('\0') != string::npos) + auto l = s.find_first_of('\0'); + if (l != string::npos) + { + if (s.find_first_not_of('\0', l) != string::npos) + return QString(); s.resize(s.find_first_of('\0')); + } + for (auto i: s) + if (i < 32) + return QString(); return QString::fromStdString(s); } return QString(); @@ -916,7 +925,9 @@ void Main::populateDebugger(eth::bytesConstRef _r) vector levels; m_codes.clear(); bytesConstRef lastExtCode; + bytesConstRef lastData; h256 lastHash; + h256 lastDataHash; auto onOp = [&](uint64_t steps, Instruction inst, unsigned newMemSize, eth::bigint gasCost, void* voidVM, void const* voidExt) { eth::VM& vm = *(eth::VM*)voidVM; @@ -928,11 +939,18 @@ void Main::populateDebugger(eth::bytesConstRef _r) if (!m_codes.count(lastHash)) m_codes[lastHash] = ext.code.toBytes(); } + if (ext.data != lastData) + { + lastData = ext.data; + lastDataHash = sha3(lastData); + if (!m_codes.count(lastDataHash)) + m_codes[lastDataHash] = ext.data.toBytes(); + } if (levels.size() < ext.level) levels.push_back(&m_history.back()); else levels.resize(ext.level); - m_history.append(WorldState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, vm.gas(), lastHash, vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels})); + m_history.append(WorldState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, vm.gas(), lastHash, lastDataHash, vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels})); }; m_currentExecution->go(onOp); initDebugger(); @@ -1243,28 +1261,28 @@ void Main::on_debug_clicked() debugFinished(); try { - u256 totalReq = value() + fee(); - eth::ClientGuard l(&*m_client); - for (auto i: m_myKeys) - if (m_client->state().balance(i.address()) >= totalReq) - { - Secret s = i.secret(); - m_executiveState = state(); - m_currentExecution = unique_ptr(new Executive(m_executiveState)); - Transaction t; - t.nonce = m_executiveState.transactionsFrom(toAddress(s)); - t.value = value(); - t.gasPrice = gasPrice(); - t.gas = ui->gas->value(); - t.data = m_data; - t.receiveAddress = isCreation() ? Address() : fromString(ui->destination->currentText()); - t.sign(s); - auto r = t.rlp(); - populateDebugger(&r); - m_currentExecution.reset(); - return; - } - statusBar()->showMessage("Couldn't make transaction: no single account contains at least the required amount."); + u256 totalReq = value() + fee(); + eth::ClientGuard l(&*m_client); + for (auto i: m_myKeys) + if (m_client->state().balance(i.address()) >= totalReq) + { + Secret s = i.secret(); + m_executiveState = state(); + m_currentExecution = unique_ptr(new Executive(m_executiveState)); + Transaction t; + t.nonce = m_executiveState.transactionsFrom(toAddress(s)); + t.value = value(); + t.gasPrice = gasPrice(); + t.gas = ui->gas->value(); + t.data = m_data; + t.receiveAddress = isCreation() ? Address() : fromString(ui->destination->currentText()); + t.sign(s); + auto r = t.rlp(); + populateDebugger(&r); + m_currentExecution.reset(); + return; + } + statusBar()->showMessage("Couldn't make transaction: no single account contains at least the required amount."); } catch (eth::Exception const& _e) { @@ -1292,9 +1310,11 @@ void Main::on_debugStepback_triggered() void Main::on_dumpTrace_triggered() { - for (auto i: m_history) - { - } + 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 << (int)ws.curPC << " " << hex << (int)(byte)ws.inst << " " << hex << (uint64_t)ws.gas << endl; } void Main::on_callStack_currentItemChanged() @@ -1308,7 +1328,7 @@ void Main::debugFinished() m_pcWarp.clear(); m_history.clear(); m_lastLevels.clear(); - m_inDebug = h256(); + m_lastCode = h256(); ui->callStack->clear(); ui->debugCode->clear(); ui->debugStack->clear(); @@ -1369,7 +1389,7 @@ void Main::updateDebugger() WorldState const& ws = ui->callStack->currentRow() > 0 ? *nws.levels[nws.levels.size() - ui->callStack->currentRow()] : nws; - if (ws.code != m_inDebug) + if (ws.code != m_lastCode) { bytes const& code = m_codes[ws.code]; QListWidget* dc = ui->debugCode; @@ -1397,11 +1417,29 @@ void Main::updateDebugger() break; // probably hit data segment } } - m_inDebug = ws.code; + m_lastCode = ws.code; + } + + if (ws.callData != m_lastData) + { + m_lastData = ws.callData; + assert(m_codes.count(ws.callData)); + ui->debugCallData->setHtml(QString::fromStdString(eth::memDump(m_codes[ws.callData], 16, true))); } for (auto i: ws.stack) - ds->insertItem(0, QString::fromStdString(toHex(((h256)i).asArray()))); + { + ostringstream s; + if (i >> 32 == 0) + s << hex << "0x" << (unsigned)i; + else if (i >> 200 == 0) + s << "0x" << (h160)right160(i); + else if (fromRaw((h256)i).size()) + s << "\"" << fromRaw((h256)i).toStdString() << "\""; + else + s << "0x" << (h256)i; + ds->insertItem(0, QString::fromStdString(s.str())); + } ui->debugMemory->setHtml(QString::fromStdString(eth::memDump(ws.memory, 16, true))); assert(m_codes.count(ws.code)); assert(m_codes[ws.code].size() > (unsigned)ws.curPC); diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index cf9e74ed5..53b7a2677 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -52,6 +52,7 @@ struct WorldState unsigned newMemSize; eth::u256 gas; eth::h256 code; + eth::h256 callData; eth::u256s stack; eth::bytes memory; eth::bigint gasCost; @@ -177,7 +178,8 @@ private: eth::State m_executiveState; std::unique_ptr m_currentExecution; - eth::h256 m_inDebug; + eth::h256 m_lastCode; + eth::h256 m_lastData; std::vector m_lastLevels; QMap m_pcWarp;