diff --git a/alethzero/Main.ui b/alethzero/Main.ui
index 68b6adae6..532333deb 100644
--- a/alethzero/Main.ui
+++ b/alethzero/Main.ui
@@ -163,6 +163,7 @@
+
@@ -518,11 +519,24 @@
Qt::Vertical
-
+
+
+ QFrame::NoFrame
+
+
+ 0
+
+
Qt::NoFocus
+
+ QFrame::NoFrame
+
+
+ 0
+
@@ -930,6 +944,21 @@
false
+
+ 6
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
-
@@ -942,6 +971,12 @@
0
+
+ QFrame::NoFrame
+
+
+ 0
+
@@ -954,11 +989,23 @@
Qt::Vertical
+
+ QFrame::NoFrame
+
+
+ 0
+
QAbstractItemView::NoSelection
+
+ QFrame::NoFrame
+
+
+ 0
+
true
@@ -967,6 +1014,12 @@
+
+ QFrame::NoFrame
+
+
+ 0
+
true
@@ -975,6 +1028,19 @@
+
+
+
+ Ubuntu Mono
+
+
+
+ QFrame::NoFrame
+
+
+ 0
+
+
-
@@ -1450,6 +1516,14 @@ font-size: 14pt
&Clear Pending
+
+
+ false
+
+
+ &Dump Standard Trace
+
+
diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp
index b5018e1a6..c3dffaa39 100644
--- a/alethzero/MainWin.cpp
+++ b/alethzero/MainWin.cpp
@@ -898,16 +898,7 @@ void Main::on_blocks_currentItemChanged()
Transaction t = st.pending()[txi];
auto r = t.rlp();
- bool done = m_currentExecution->setup(&r);
- if (!done)
- {
- debugFinished();
- auto startGas = m_currentExecution->vm().gas();
- for (; !done; done = m_currentExecution->go(1))
- m_history.append(WorldState({m_currentExecution->vm().curPC(), m_currentExecution->vm().gas(), startGas - m_currentExecution->vm().gas(), m_currentExecution->vm().stack(), m_currentExecution->vm().memory(), m_currentExecution->state().storage(m_currentExecution->ext().myAddress)}));
- initDebugger();
- updateDebugger();
- }
+ populateDebugger(&r);
m_currentExecution.reset();
}
@@ -916,6 +907,39 @@ void Main::on_blocks_currentItemChanged()
}
}
+void Main::populateDebugger(eth::bytesConstRef _r)
+{
+ bool done = m_currentExecution->setup(_r);
+ if (!done)
+ {
+ debugFinished();
+ vector levels;
+ m_codes.clear();
+ bytesConstRef lastExtCode;
+ h256 lastHash;
+ auto onOp = [&](uint64_t steps, Instruction inst, unsigned newMemSize, eth::bigint gasCost, void* voidVM, void const* voidExt)
+ {
+ eth::VM& vm = *(eth::VM*)voidVM;
+ eth::ExtVM const& ext = *(eth::ExtVM const*)voidExt;
+ if (ext.code != lastExtCode)
+ {
+ lastExtCode = ext.code;
+ lastHash = sha3(lastExtCode);
+ if (!m_codes.count(lastHash))
+ m_codes[lastHash] = ext.code.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_currentExecution->go(onOp);
+ initDebugger();
+ updateDebugger();
+ }
+}
+
void Main::on_contracts_currentItemChanged()
{
ui->contractInfo->clear();
@@ -1236,15 +1260,7 @@ void Main::on_debug_clicked()
t.receiveAddress = isCreation() ? Address() : fromString(ui->destination->currentText());
t.sign(s);
auto r = t.rlp();
- bool done = m_currentExecution->setup(&r);
- if (!done)
- {
- auto startGas = m_currentExecution->vm().gas();
- for (; !done; done = m_currentExecution->go(1))
- m_history.append(WorldState({m_currentExecution->vm().curPC(), m_currentExecution->vm().gas(), startGas - m_currentExecution->vm().gas(), m_currentExecution->vm().stack(), m_currentExecution->vm().memory(), m_currentExecution->state().storage(m_currentExecution->ext().myAddress)}));
- initDebugger();
- updateDebugger();
- }
+ populateDebugger(&r);
m_currentExecution.reset();
return;
}
@@ -1265,17 +1281,35 @@ void Main::on_create_triggered()
void Main::on_debugStep_triggered()
{
ui->debugTimeline->setValue(ui->debugTimeline->value() + 1);
+ ui->callStack->setCurrentRow(0);
}
void Main::on_debugStepback_triggered()
{
ui->debugTimeline->setValue(ui->debugTimeline->value() - 1);
+ ui->callStack->setCurrentRow(0);
+}
+
+void Main::on_dumpTrace_triggered()
+{
+ for (auto i: m_history)
+ {
+ }
+}
+
+void Main::on_callStack_currentItemChanged()
+{
+ updateDebugger();
}
void Main::debugFinished()
{
+ m_codes.clear();
m_pcWarp.clear();
m_history.clear();
+ m_lastLevels.clear();
+ m_inDebug = h256();
+ ui->callStack->clear();
ui->debugCode->clear();
ui->debugStack->clear();
ui->debugMemory->setHtml("");
@@ -1283,6 +1317,7 @@ void Main::debugFinished()
ui->debugStateInfo->setText("");
// ui->send->setEnabled(true);
ui->debugStep->setEnabled(false);
+ ui->dumpTrace->setEnabled(false);
ui->debugStepback->setEnabled(false);
ui->debugPanel->setEnabled(false);
}
@@ -1293,30 +1328,66 @@ void Main::initDebugger()
if (m_history.size())
{
ui->debugStep->setEnabled(true);
+ ui->dumpTrace->setEnabled(true);
ui->debugStepback->setEnabled(true);
ui->debugPanel->setEnabled(true);
ui->debugCode->setEnabled(false);
ui->debugTimeline->setMinimum(0);
ui->debugTimeline->setMaximum(m_history.size() - 1);
ui->debugTimeline->setValue(0);
+ }
+}
+
+void Main::on_debugTimeline_valueChanged()
+{
+ updateDebugger();
+}
+
+void Main::updateDebugger()
+{
+ if (m_history.size())
+ {
+ QListWidget* ds = ui->debugStack;
+ ds->clear();
- QListWidget* dc = ui->debugCode;
- dc->clear();
- if (m_currentExecution)
+ WorldState const& nws = m_history[ui->debugTimeline->value()];
+
+ if (m_lastLevels != nws.levels || !ui->callStack->count())
{
- for (unsigned i = 0; i <= m_currentExecution->ext().code.size(); ++i)
+ m_lastLevels = nws.levels;
+ ui->callStack->clear();
+ for (unsigned i = 0; i <= nws.levels.size(); ++i)
{
- byte b = i < m_currentExecution->ext().code.size() ? m_currentExecution->ext().code[i] : 0;
+ WorldState const& s = i ? *nws.levels[nws.levels.size() - i] : nws;
+ ostringstream out;
+ out << s.cur.abridged();
+ if (i)
+ out << " @0x" << hex << s.curPC;
+ ui->callStack->addItem(QString::fromStdString(out.str()));
+ }
+ }
+
+ WorldState const& ws = ui->callStack->currentRow() > 0 ? *nws.levels[nws.levels.size() - ui->callStack->currentRow()] : nws;
+
+ if (ws.code != m_inDebug)
+ {
+ bytes const& code = m_codes[ws.code];
+ QListWidget* dc = ui->debugCode;
+ dc->clear();
+ m_pcWarp.clear();
+ for (unsigned i = 0; i <= code.size(); ++i)
+ {
+ byte b = i < code.size() ? code[i] : 0;
try
{
QString s = c_instructionInfo.at((Instruction)b).name;
- m_pcWarp[i] = dc->count();
ostringstream out;
out << hex << setw(4) << setfill('0') << i;
+ m_pcWarp[i] = dc->count();
if (b >= (byte)Instruction::PUSH1 && b <= (byte)Instruction::PUSH32)
{
unsigned bc = b - (byte)Instruction::PUSH1 + 1;
- s = "PUSH 0x" + QString::fromStdString(toHex(bytesConstRef(&m_currentExecution->ext().code[i + 1], bc)));
+ s = "PUSH 0x" + QString::fromStdString(toHex(bytesConstRef(&code[i + 1], bc)));
i += bc;
}
dc->addItem(QString::fromStdString(out.str()) + " " + s);
@@ -1326,30 +1397,20 @@ void Main::initDebugger()
break; // probably hit data segment
}
}
+ m_inDebug = ws.code;
}
- }
-}
-
-void Main::on_debugTimeline_valueChanged()
-{
- updateDebugger();
-}
-
-void Main::updateDebugger()
-{
- if (m_history.size())
- {
- QListWidget* ds = ui->debugStack;
- ds->clear();
-
- WorldState const& ws = m_history[ui->debugTimeline->value()];
for (auto i: ws.stack)
ds->insertItem(0, QString::fromStdString(toHex(((h256)i).asArray())));
ui->debugMemory->setHtml(QString::fromStdString(eth::memDump(ws.memory, 16, true)));
- ui->debugCode->setCurrentRow(m_pcWarp[(unsigned)ws.curPC]);
+ assert(m_codes.count(ws.code));
+ assert(m_codes[ws.code].size() > (unsigned)ws.curPC);
+ int l = m_pcWarp[(unsigned)ws.curPC];
+ ui->debugCode->setCurrentRow(max(0, l - 5));
+ ui->debugCode->setCurrentRow(min(ui->debugCode->count() - 1, l + 5));
+ ui->debugCode->setCurrentRow(l);
ostringstream ss;
- ss << hex << "PC: 0x" << ws.curPC << " | GAS: " << dec << ws.gas << " | (- " << dec << ws.gasUsed << ")";
+ ss << dec << "STEP: " << ws.steps << " | PC: 0x" << hex << ws.curPC << " : " << c_instructionInfo.at(ws.inst).name << " | ADDMEM: " << dec << ws.newMemSize << " words | COST: " << dec << ws.gasCost << " | GAS: " << dec << ws.gas;
ui->debugStateInfo->setText(QString::fromStdString(ss.str()));
stringstream s;
diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h
index 6cd1043fe..cf9e74ed5 100644
--- a/alethzero/MainWin.h
+++ b/alethzero/MainWin.h
@@ -21,7 +21,8 @@
#pragma once
-//#include
+
+#include