Browse Source

Merge pull request #1208 from arkpar/mix_srci

Mix: solidity debugger inspectors
cl-refactor
Arkadiy Paronyan 10 years ago
parent
commit
8ec399fae8
  1. 89
      mix/ClientModel.cpp
  2. 2
      mix/ClientModel.h
  3. 107
      mix/CodeModel.cpp
  4. 31
      mix/CodeModel.h
  5. 7
      mix/DebuggingStateWrapper.cpp
  6. 45
      mix/DebuggingStateWrapper.h
  7. 74
      mix/qml/CallStack.qml
  8. 175
      mix/qml/Debugger.qml
  9. 4
      mix/qml/StatusPane.qml
  10. 69
      mix/qml/StorageView.qml
  11. 31
      mix/qml/js/Debugger.js
  12. 2
      mix/res.qrc

89
mix/ClientModel.cpp

@ -37,7 +37,6 @@
#include "QVariableDefinition.h"
#include "ContractCallDataEncoder.h"
#include "CodeModel.h"
#include "ClientModel.h"
#include "QEther.h"
#include "Web3Server.h"
#include "ClientModel.h"
@ -318,19 +317,28 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t)
QDebugData* debugData = new QDebugData();
QQmlEngine::setObjectOwnership(debugData, QQmlEngine::JavaScriptOwnership);
QList<QCode*> codes;
QList<QHash<int, int>> codeMaps;
QList<AssemblyItems> codeItems;
QList<CompiledContract const*> contracts;
for (MachineCode const& code: _t.executionCode)
{
codes.push_back(QMachineState::getHumanReadableCode(debugData, code.address, code.code));
QHash<int, int> codeMap;
codes.push_back(QMachineState::getHumanReadableCode(debugData, code.address, code.code, codeMap));
codeMaps.push_back(std::move(codeMap));
//try to resolve contract for source level debugging
auto nameIter = m_contractNames.find(code.address);
if (nameIter != m_contractNames.end())
{
CompiledContract const& compilerRes = m_context->codeModel()->contract(nameIter->second);
eth::AssemblyItems assemblyItems = !_t.isConstructor() ? compilerRes.assemblyItems() : compilerRes.constructorAssemblyItems();
QVariantList locations;
for (eth::AssemblyItem const& item: assemblyItems)
locations.push_back(QVariant::fromValue(new QSourceLocation(debugData, item.getLocation().start, item.getLocation().end)));
codes.back()->setLocations(compilerRes.documentId(), std::move(locations));
codes.back()->setDocument(compilerRes.documentId());
codeItems.push_back(std::move(assemblyItems));
contracts.push_back(&compilerRes);
}
else
{
codeItems.push_back(AssemblyItems());
contracts.push_back(nullptr);
}
}
@ -339,18 +347,77 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t)
data.push_back(QMachineState::getDebugCallData(debugData, d));
QVariantList states;
QStringList solCallStack;
std::map<int, SolidityDeclaration> solLocals; //<stack pos, declaration>
QList<int> returnStack;
unsigned prevInstructionIndex = 0;
for (MachineState const& s: _t.machineStates)
states.append(QVariant::fromValue(new QMachineState(debugData, s, codes[s.codeIndex], data[s.dataIndex])));
{
int instructionIndex = codeMaps[s.codeIndex][static_cast<unsigned>(s.curPC)];
QSolState* solState = nullptr;
if (!codeItems[s.codeIndex].empty() && contracts[s.codeIndex])
{
CompiledContract const* contract = contracts[s.codeIndex];
AssemblyItem const& instruction = codeItems[s.codeIndex][instructionIndex];
debugData->setStates(std::move(states));
if (instruction.type() == dev::eth::Push && !instruction.data())
{
//register new local variable initialization
auto localIter = contract->locals().find(LocationPair(instruction.getLocation().start, instruction.getLocation().end));
if (localIter != contract->locals().end())
solLocals[s.stack.size()] = localIter.value();
}
//QList<QVariableDefinition*> returnParameters;
//returnParameters = encoder.decode(f->returnParameters(), debuggingContent.returnValue);
if (instruction.type() == dev::eth::Tag) //TODO: use annotations
{
//track calls into functions
auto functionIter = contract->functions().find(LocationPair(instruction.getLocation().start, instruction.getLocation().end));
if (functionIter != contract->functions().end())
{
QString functionName = functionIter.value();
solCallStack.push_back(functionName);
returnStack.push_back(prevInstructionIndex + 1);
}
else if (!returnStack.empty() && instructionIndex == returnStack.back())
{
returnStack.pop_back();
solCallStack.pop_back();
}
}
//format solidity context values
QStringList locals;
for(auto l: solLocals)
if (l.first < (int)s.stack.size())
locals.push_back(l.second.name + "\t" + formatValue(l.second.type, s.stack[l.first]));
QStringList storage;
for(auto st: s.storage)
{
if (st.first < std::numeric_limits<unsigned>::max())
{
auto storageIter = contract->storage().find(static_cast<unsigned>(st.first));
if (storageIter != contract->storage().end())
storage.push_back(storageIter.value().name + "\t" + formatValue(storageIter.value().type, st.second));
}
}
prevInstructionIndex = instructionIndex;
solState = new QSolState(debugData, storage, solCallStack, locals, instruction.getLocation().start, instruction.getLocation().end);
}
states.append(QVariant::fromValue(new QMachineState(debugData, instructionIndex, s, codes[s.codeIndex], data[s.dataIndex], solState)));
}
//collect states for last transaction
debugData->setStates(std::move(states));
debugDataReady(debugData);
}
QString ClientModel::formatValue(SolidityType const&, dev::u256 const& _value)
{
return QString::fromStdString(prettyU256(_value));
}
void ClientModel::emptyRecord()
{
debugDataReady(new QDebugData());

2
mix/ClientModel.h

@ -41,6 +41,7 @@ class QEther;
class QDebugData;
class MixClient;
class QVariableDefinition;
struct SolidityType;
/// Backend transaction config class
struct TransactionSettings
@ -198,6 +199,7 @@ private:
void onNewTransaction();
void onStateReset();
void showDebuggerForTransaction(ExecutionResult const& _t);
QString formatValue(SolidityType const& _type, dev::u256 const& _value);
AppContext* m_context;
std::atomic<bool> m_running;

107
mix/CodeModel.cpp

@ -25,7 +25,10 @@
#include <QDebug>
#include <QApplication>
#include <QtQml>
#include <libdevcore/Common.h>
#include <libevmcore/SourceLocation.h>
#include <libsolidity/AST.h>
#include <libsolidity/ASTVisitor.h>
#include <libsolidity/CompilerStack.h>
#include <libsolidity/SourceReferenceFormatter.h>
#include <libsolidity/InterfaceHandler.h>
@ -43,6 +46,91 @@ using namespace dev::mix;
const std::set<std::string> c_predefinedContracts =
{ "Config", "Coin", "CoinReg", "coin", "service", "owned", "mortal", "NameReg", "named", "std", "configUser" };
namespace
{
using namespace dev::solidity;
class CollectDeclarationsVisitor: public ASTConstVisitor
{
public:
CollectDeclarationsVisitor(QHash<LocationPair, QString>* _functions, QHash<LocationPair, SolidityDeclaration>* _locals, QHash<unsigned, SolidityDeclaration>* _storage):
m_functions(_functions), m_locals(_locals), m_storage(_storage), m_functionScope(false), m_storageSlot(0) {}
private:
QHash<LocationPair, QString>* m_functions;
QHash<LocationPair, SolidityDeclaration>* m_locals;
QHash<unsigned, SolidityDeclaration>* m_storage;
bool m_functionScope;
uint m_storageSlot;
LocationPair nodeLocation(ASTNode const& _node)
{
return LocationPair(_node.getLocation().start, _node.getLocation().end);
}
SolidityType nodeType(Type const* _type)
{
if (!_type)
return SolidityType { SolidityType::Type::UnsignedInteger, 32 };
switch (_type->getCategory())
{
case Type::Category::Integer:
{
IntegerType const* it = dynamic_cast<IntegerType const*>(_type);
unsigned size = it->getNumBits() / 8;
SolidityType::Type typeCode = it->isAddress() ? SolidityType::Type::Address : it->isHash() ? SolidityType::Type::Hash : it->isSigned() ? SolidityType::Type::SignedInteger : SolidityType::Type::UnsignedInteger;
return SolidityType { typeCode, size };
}
case Type::Category::Bool:
return SolidityType { SolidityType::Type::Bool, _type->getSizeOnStack() * 32 };
case Type::Category::String:
{
StaticStringType const* s = dynamic_cast<StaticStringType const*>(_type);
return SolidityType { SolidityType::Type::String, static_cast<unsigned>(s->getNumBytes()) };
}
case Type::Category::Contract:
return SolidityType { SolidityType::Type::Address, _type->getSizeOnStack() * 32 };
case Type::Category::Array:
case Type::Category::Enum:
case Type::Category::Function:
case Type::Category::IntegerConstant:
case Type::Category::Magic:
case Type::Category::Mapping:
case Type::Category::Modifier:
case Type::Category::Real:
case Type::Category::Struct:
case Type::Category::TypeType:
case Type::Category::Void:
default:
return SolidityType { SolidityType::Type::UnsignedInteger, 32 };
}
}
virtual bool visit(FunctionDefinition const& _node)
{
m_functions->insert(nodeLocation(_node), QString::fromStdString(_node.getName()));
m_functionScope = true;
return true;
}
virtual void endVisit(FunctionDefinition const&)
{
m_functionScope = false;
}
virtual bool visit(VariableDeclaration const& _node)
{
SolidityDeclaration decl;
decl.type = nodeType(_node.getType().get());
decl.name = QString::fromStdString(_node.getName());
if (m_functionScope)
m_locals->insert(nodeLocation(_node), decl);
else
m_storage->insert(m_storageSlot++, decl);
return true;
}
};
}
void BackgroundWorker::queueCodeChange(int _jobId)
{
m_model->runCompilationJob(_jobId);
@ -52,18 +140,23 @@ CompiledContract::CompiledContract(const dev::solidity::CompilerStack& _compiler
QObject(nullptr),
m_sourceHash(qHash(_source))
{
auto const& contractDefinition = _compiler.getContractDefinition(_contractName.toStdString());
std::string name = _contractName.toStdString();
auto const& contractDefinition = _compiler.getContractDefinition(name);
m_contract.reset(new QContractDefinition(&contractDefinition));
QQmlEngine::setObjectOwnership(m_contract.get(), QQmlEngine::CppOwnership);
m_bytes = _compiler.getBytecode(_contractName.toStdString());
m_assemblyItems = _compiler.getRuntimeAssemblyItems(_contractName.toStdString());
m_constructorAssemblyItems = _compiler.getAssemblyItems(_contractName.toStdString());
m_assemblyItems = _compiler.getRuntimeAssemblyItems(name);
m_constructorAssemblyItems = _compiler.getAssemblyItems(name);
dev::solidity::InterfaceHandler interfaceHandler;
m_contractInterface = QString::fromStdString(*interfaceHandler.getABIInterface(contractDefinition));
if (m_contractInterface.isEmpty())
m_contractInterface = "[]";
if (contractDefinition.getLocation().sourceName.get())
m_documentId = QString::fromStdString(*contractDefinition.getLocation().sourceName);
CollectDeclarationsVisitor visitor(&m_functions, &m_locals, &m_storage);
contractDefinition.accept(visitor);
}
QString CompiledContract::codeHex() const
@ -121,12 +214,11 @@ void CodeModel::reset(QVariantMap const& _documents)
void CodeModel::registerCodeChange(QString const& _documentId, QString const& _code)
{
{
Guard l(x_contractMap);
CompiledContract* contract = m_contractMap.value(_documentId);
CompiledContract* contract = contractByDocumentId(_documentId);
if (contract != nullptr && contract->m_sourceHash == qHash(_code))
return;
{
Guard pl(x_pendingContracts);
m_pendingContracts[_documentId] = _code;
}
@ -196,7 +288,8 @@ void CodeModel::runCompilationJob(int _jobId)
if (c_predefinedContracts.count(n) != 0)
continue;
QString name = QString::fromStdString(n);
auto sourceIter = m_pendingContracts.find(name);
QString sourceName = QString::fromStdString(*cs.getContractDefinition(n).getLocation().sourceName);
auto sourceIter = m_pendingContracts.find(sourceName);
QString source = sourceIter != m_pendingContracts.end() ? sourceIter->second : QString();
CompiledContract* contract = new CompiledContract(cs, name, source);
QQmlEngine::setObjectOwnership(contract, QQmlEngine::CppOwnership);

31
mix/CodeModel.h

@ -64,6 +64,29 @@ private:
CodeModel* m_model;
};
using LocationPair = QPair<int, int>;
struct SolidityType
{
enum class Type //TODO: arrays and structs
{
SignedInteger,
UnsignedInteger,
Hash,
Bool,
Address,
String,
};
Type type;
unsigned size; //bytes
};
struct SolidityDeclaration
{
QString name;
SolidityType type;
};
///Compilation result model. Contains all the compiled contract data required by UI
class CompiledContract: public QObject
{
@ -93,6 +116,10 @@ public:
/// @returns contract source Id
QString documentId() const { return m_documentId; }
QHash<LocationPair, QString> const& functions() const { return m_functions; }
QHash<LocationPair, SolidityDeclaration> const& locals() const { return m_locals; }
QHash<unsigned, SolidityDeclaration> const& storage() const { return m_storage; }
private:
uint m_sourceHash;
std::shared_ptr<QContractDefinition> m_contract;
@ -102,11 +129,13 @@ private:
QString m_documentId;
eth::AssemblyItems m_assemblyItems;
eth::AssemblyItems m_constructorAssemblyItems;
QHash<LocationPair, QString> m_functions;
QHash<LocationPair, SolidityDeclaration> m_locals;
QHash<unsigned, SolidityDeclaration> m_storage;
friend class CodeModel;
};
using ContractMap = QHash<QString, CompiledContract*>;
/// Code compilation model. Compiles contracts in background an provides compiled contract data

7
mix/DebuggingStateWrapper.cpp

@ -69,7 +69,7 @@ namespace
}
}
QCode* QMachineState::getHumanReadableCode(QObject* _owner, const Address& _address, const bytes& _code)
QCode* QMachineState::getHumanReadableCode(QObject* _owner, const Address& _address, const bytes& _code, QHash<int, int>& o_codeMap)
{
QVariantList codeStr;
for (unsigned i = 0; i <= _code.size(); ++i)
@ -80,14 +80,15 @@ QCode* QMachineState::getHumanReadableCode(QObject* _owner, const Address& _addr
QString s = QString::fromStdString(instructionInfo((Instruction)b).name);
std::ostringstream out;
out << std::hex << std::setw(4) << std::setfill('0') << i;
int line = 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;
}
codeStr.append(QVariant::fromValue(new QInstruction(_owner, QString::fromStdString(out.str()) + " " + s, line)));
o_codeMap[offset] = codeStr.size();
codeStr.append(QVariant::fromValue(new QInstruction(_owner, QString::fromStdString(out.str()) + " " + s)));
}
catch (...)
{

45
mix/DebuggingStateWrapper.h

@ -26,12 +26,12 @@
#include <boost/asio.hpp>
#include <QStringList>
#include <QMap>
#include <QHash>
#include <libdevcore/Common.h>
#include <libethereum/State.h>
#include <libethereum/Executive.h>
#include "MachineStates.h"
#include "QVariableDefinition.h"
#include "MixClient.h"
#include "QBigInt.h"
namespace dev
@ -46,32 +46,39 @@ class QInstruction: public QObject
{
Q_OBJECT
Q_PROPERTY(QString line MEMBER m_line CONSTANT)
Q_PROPERTY(int processIndex MEMBER m_processIndex CONSTANT)
public:
QInstruction(QObject* _owner, QString _line, int _processIndex): QObject(_owner), m_line(_line), m_processIndex(_processIndex) {}
QInstruction(QObject* _owner, QString _line): QObject(_owner), m_line(_line) {}
private:
QString m_line;
int m_processIndex;
};
class QSourceLocation: public QObject
/**
* @brief Solidity state
*/
class QSolState: public QObject
{
Q_OBJECT
Q_PROPERTY(QStringList storage MEMBER m_storage CONSTANT)
Q_PROPERTY(QStringList callStack MEMBER m_callStack CONSTANT)
Q_PROPERTY(QStringList locals MEMBER m_locals CONSTANT)
Q_PROPERTY(int start MEMBER m_start CONSTANT)
Q_PROPERTY(int end MEMBER m_end CONSTANT)
public:
QSourceLocation(QObject* _owner, int _start, int _end): QObject(_owner), m_start(_start), m_end(_end) {}
QSolState(QObject* _parent, QStringList const& _storage, QStringList const& _callStack, QStringList const& _locals, int _start, int _end):
QObject(_parent), m_storage(_storage), m_callStack(_callStack), m_locals(_locals), m_start(_start), m_end(_end)
{ }
private:
QStringList m_storage;
QStringList m_callStack;
QStringList m_locals;
int m_start;
int m_end;
};
/**
* @brief Shared container for lines
*/
@ -79,19 +86,17 @@ class QCode: public QObject
{
Q_OBJECT
Q_PROPERTY(QVariantList instructions MEMBER m_instructions CONSTANT)
Q_PROPERTY(QVariantList locations MEMBER m_locations CONSTANT)
Q_PROPERTY(QString address MEMBER m_address CONSTANT)
Q_PROPERTY(QString documentId MEMBER m_document CONSTANT)
public:
QCode(QObject* _owner, QString const& _address, QVariantList&& _instrunctions): QObject(_owner), m_instructions(_instrunctions), m_address(_address) {}
void setLocations(QString const& _document, QVariantList&& _locations) { m_document = _document; m_locations = _locations; }
void setDocument(QString const& _documentId) { m_document = _documentId; }
private:
QVariantList m_instructions;
QString m_address;
QString m_document;
QVariantList m_locations;
};
/**
@ -133,6 +138,7 @@ class QMachineState: public QObject
Q_OBJECT
Q_PROPERTY(int step READ step CONSTANT)
Q_PROPERTY(int curPC READ curPC CONSTANT)
Q_PROPERTY(int instructionIndex MEMBER m_instructionIndex CONSTANT)
Q_PROPERTY(QBigInt* gasCost READ gasCost CONSTANT)
Q_PROPERTY(QBigInt* gas READ gas CONSTANT)
Q_PROPERTY(QString instruction READ instruction CONSTANT)
@ -146,10 +152,11 @@ class QMachineState: public QObject
Q_PROPERTY(QVariantList levels READ levels CONSTANT)
Q_PROPERTY(unsigned codeIndex READ codeIndex CONSTANT)
Q_PROPERTY(unsigned dataIndex READ dataIndex CONSTANT)
Q_PROPERTY(QObject* solidity MEMBER m_solState CONSTANT)
public:
QMachineState(QObject* _owner, MachineState const& _state, QCode* _code, QCallData* _callData):
QObject(_owner), m_state(_state), m_code(_code), m_callData(_callData) {}
QMachineState(QObject* _owner, int _instructionIndex, MachineState const& _state, QCode* _code, QCallData* _callData, QSolState* _solState):
QObject(_owner), m_instructionIndex(_instructionIndex), m_state(_state), m_code(_code), m_callData(_callData), m_solState(_solState) { }
/// Get the step of this machine states.
int step() { return (int)m_state.steps; }
/// Get the proccessed code index.
@ -168,7 +175,7 @@ public:
QStringList debugStorage();
/// Get memory.
QVariantList debugMemory();
/// get end of debug information.
/// Get end of debug information.
QString endOfDebug();
/// Get the new memory size.
QBigInt* newMemSize();
@ -177,18 +184,18 @@ public:
/// Get all previous steps.
QVariantList levels();
/// Get the current processed machine state.
MachineState state() { return m_state; }
/// Set the current processed machine state.
void setState(MachineState _state) { m_state = _state; }
MachineState const& state() const { return m_state; }
/// Convert all machine states in human readable code.
static QCode* getHumanReadableCode(QObject* _owner, const Address& _address, const bytes& _code);
static QCode* getHumanReadableCode(QObject* _owner, const Address& _address, const bytes& _code, QHash<int, int>& o_codeMap);
/// Convert call data into human readable form
static QCallData* getDebugCallData(QObject* _owner, bytes const& _data);
private:
int m_instructionIndex;
MachineState m_state;
QCode* m_code;
QCallData* m_callData;
QSolState* m_solState;
};
}

74
mix/qml/CallStack.qml

@ -0,0 +1,74 @@
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Layouts 1.1
import "."
DebugInfoList
{
id: callStack
collapsible: true
title : qsTr("Call Stack")
enableSelection: true
itemDelegate:
Item {
anchors.fill: parent
Rectangle {
anchors.fill: parent
color: "#4A90E2"
visible: styleData.selected;
}
RowLayout
{
id: row
anchors.fill: parent
Rectangle
{
color: "#f7f7f7"
Layout.fillWidth: true
Layout.minimumWidth: 30
Layout.maximumWidth: 30
Text {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
font.family: "monospace"
anchors.leftMargin: 5
color: "#4a4a4a"
text: styleData.row;
font.pointSize: DebuggerPaneStyle.general.basicFontSize
width: parent.width - 5
elide: Text.ElideRight
}
}
Rectangle
{
color: "transparent"
Layout.fillWidth: true
Layout.minimumWidth: parent.width - 30
Layout.maximumWidth: parent.width - 30
Text {
anchors.leftMargin: 5
width: parent.width - 5
wrapMode: Text.NoWrap
anchors.left: parent.left
font.family: "monospace"
anchors.verticalCenter: parent.verticalCenter
color: "#4a4a4a"
text: styleData.value;
elide: Text.ElideRight
font.pointSize: DebuggerPaneStyle.general.basicFontSize
}
}
}
Rectangle {
anchors.top: row.bottom
width: parent.width;
height: 1;
color: "#cccccc"
anchors.bottom: parent.bottom
}
}
}

175
mix/qml/Debugger.qml

@ -29,6 +29,7 @@ Rectangle {
onAssemblyModeChanged:
{
Debugger.updateMode();
machineStates.updateHeight();
}
function displayCompilationErrorIfAny()
@ -90,6 +91,9 @@ Rectangle {
property alias memoryDumpHeightSettings: memoryRect.height
property alias callDataHeightSettings: callDataRect.height
property alias transactionLogVisible: transactionLog.visible
property alias solCallStackHeightSettings: solStackRect.height
property alias solStorageHeightSettings: solStorageRect.height
property alias solLocalsHeightSettings: solLocalsRect.height
}
Rectangle
@ -183,8 +187,12 @@ Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
function updateHeight() {
statesLayout.height = buttonRow.childrenRect.height + assemblyCodeRow.childrenRect.height +
callStackRect.childrenRect.height + storageRect.childrenRect.height + memoryRect.childrenRect.height + callDataRect.childrenRect.height + 120;
var h = buttonRow.childrenRect.height;
if (assemblyMode)
h += assemblyCodeRow.childrenRect.height + callStackRect.childrenRect.height + storageRect.childrenRect.height + memoryRect.childrenRect.height + callDataRect.childrenRect.height;
else
h += solStackRect.childrenRect.height + solLocalsRect.childrenRect.height + solStorageRect.childrenRect.height;
statesLayout.height = h + 120;
}
Component.onCompleted: updateHeight();
@ -546,153 +554,78 @@ Rectangle {
Rectangle
{
id: callStackRect;
id: solStackRect;
color: "transparent"
Layout.minimumHeight: 25
Layout.maximumHeight: 800
onHeightChanged: machineStates.updateHeight();
DebugInfoList
{
id: callStack
collapsible: true
anchors.fill: parent
title : qsTr("Call Stack")
enableSelection: true
onRowActivated: Debugger.displayFrame(index);
itemDelegate:
Item {
anchors.fill: parent
Rectangle {
visible: !assemblyMode
CallStack {
anchors.fill: parent
color: "#4A90E2"
visible: styleData.selected;
id: solCallStack
}
}
RowLayout
{
id: row
anchors.fill: parent
Rectangle
{
color: "#f7f7f7"
Layout.fillWidth: true
Layout.minimumWidth: 30
Layout.maximumWidth: 30
Text {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
font.family: "monospace"
anchors.leftMargin: 5
color: "#4a4a4a"
text: styleData.row;
font.pointSize: DebuggerPaneStyle.general.basicFontSize
width: parent.width - 5
elide: Text.ElideRight
id: solLocalsRect;
color: "transparent"
Layout.minimumHeight: 25
Layout.maximumHeight: 800
onHeightChanged: machineStates.updateHeight();
visible: !assemblyMode
StorageView {
title : qsTr("Locals")
anchors.fill: parent
id: solLocals
}
}
Rectangle
{
id: solStorageRect;
color: "transparent"
Layout.fillWidth: true
Layout.minimumWidth: parent.width - 30
Layout.maximumWidth: parent.width - 30
Text {
anchors.leftMargin: 5
width: parent.width - 5
wrapMode: Text.NoWrap
anchors.left: parent.left
font.family: "monospace"
anchors.verticalCenter: parent.verticalCenter
color: "#4a4a4a"
text: styleData.value;
elide: Text.ElideRight
font.pointSize: DebuggerPaneStyle.general.basicFontSize
}
}
}
Rectangle {
anchors.top: row.bottom
width: parent.width;
height: 1;
color: "#cccccc"
anchors.bottom: parent.bottom
}
}
Layout.minimumHeight: 25
Layout.maximumHeight: 800
onHeightChanged: machineStates.updateHeight();
visible: !assemblyMode
StorageView {
title : qsTr("Members")
anchors.fill: parent
id: solStorage
}
}
Rectangle
{
id: storageRect
id: callStackRect;
color: "transparent"
width: parent.width
Layout.minimumHeight: 25
Layout.maximumHeight: 800
onHeightChanged: machineStates.updateHeight();
DebugInfoList
{
id: storage
anchors.fill: parent
collapsible: true
title : qsTr("Storage")
itemDelegate:
Item {
anchors.fill: parent
RowLayout
{
id: row
visible: assemblyMode
CallStack {
anchors.fill: parent
Rectangle
{
color: "#f7f7f7"
Layout.fillWidth: true
Layout.minimumWidth: parent.width / 2
Layout.maximumWidth: parent.width / 2
Text {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
font.family: "monospace"
anchors.leftMargin: 5
color: "#4a4a4a"
text: styleData.value.split('\t')[0];
font.pointSize: DebuggerPaneStyle.general.basicFontSize
width: parent.width - 5
elide: Text.ElideRight
id: callStack
onRowActivated: Debugger.displayFrame(index);
}
}
Rectangle
{
id: storageRect
color: "transparent"
Layout.fillWidth: true
Layout.minimumWidth: parent.width / 2
Layout.maximumWidth: parent.width / 2
Text {
maximumLineCount: 1
clip: true
anchors.leftMargin: 5
width: parent.width - 5
wrapMode: Text.WrapAnywhere
anchors.left: parent.left
font.family: "monospace"
anchors.verticalCenter: parent.verticalCenter
color: "#4a4a4a"
text: styleData.value.split('\t')[1];
elide: Text.ElideRight
font.pointSize: DebuggerPaneStyle.general.basicFontSize
}
}
}
Rectangle {
anchors.top: row.bottom
width: parent.width;
height: 1;
color: "#cccccc"
anchors.bottom: parent.bottom
}
}
width: parent.width
Layout.minimumHeight: 25
Layout.maximumHeight: 800
onHeightChanged: machineStates.updateHeight();
visible: assemblyMode
StorageView {
anchors.fill: parent
id: storage
}
}
@ -704,6 +637,7 @@ Rectangle {
Layout.minimumHeight: 25
Layout.maximumHeight: 800
onHeightChanged: machineStates.updateHeight();
visible: assemblyMode
DebugInfoList {
id: memoryDump
anchors.fill: parent
@ -726,6 +660,7 @@ Rectangle {
Layout.minimumHeight: 25
Layout.maximumHeight: 800
onHeightChanged: machineStates.updateHeight();
visible: assemblyMode
DebugInfoList {
id: callDataDump
anchors.fill: parent

4
mix/qml/StatusPane.qml

@ -159,8 +159,8 @@ Rectangle {
color: "transparent"
width: 100
height: parent.height
anchors.top: statusHeader.top
anchors.right: statusHeader.right
anchors.top: parent.top
anchors.right: parent.right
RowLayout
{
anchors.fill: parent

69
mix/qml/StorageView.qml

@ -0,0 +1,69 @@
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Layouts 1.1
import "."
DebugInfoList
{
id: storage
collapsible: true
title : qsTr("Storage")
itemDelegate:
Item {
anchors.fill: parent
RowLayout
{
id: row
anchors.fill: parent
Rectangle
{
color: "#f7f7f7"
Layout.fillWidth: true
Layout.minimumWidth: parent.width / 2
Layout.maximumWidth: parent.width / 2
Text {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
font.family: "monospace"
anchors.leftMargin: 5
color: "#4a4a4a"
text: styleData.value.split('\t')[0];
font.pointSize: DebuggerPaneStyle.general.basicFontSize
width: parent.width - 5
elide: Text.ElideRight
}
}
Rectangle
{
color: "transparent"
Layout.fillWidth: true
Layout.minimumWidth: parent.width / 2
Layout.maximumWidth: parent.width / 2
Text {
maximumLineCount: 1
clip: true
anchors.leftMargin: 5
width: parent.width - 5
wrapMode: Text.WrapAnywhere
anchors.left: parent.left
font.family: "monospace"
anchors.verticalCenter: parent.verticalCenter
color: "#4a4a4a"
text: styleData.value.split('\t')[1];
elide: Text.ElideRight
font.pointSize: DebuggerPaneStyle.general.basicFontSize
}
}
}
Rectangle {
anchors.top: row.bottom
width: parent.width;
height: 1;
color: "#cccccc"
anchors.bottom: parent.bottom
}
}
}

31
mix/qml/js/Debugger.js

@ -4,7 +4,6 @@
var currentSelectedState = null;
var currentDisplayedState = null;
var debugData = null;
var codeMap = null;
var locations = [];
var locationMap = {};
var breakpoints = {};
@ -56,7 +55,7 @@ function initLocations()
for (var i = 0; i < debugData.states.length - 1; i++) {
var code = debugData.states[i].code;
var location = code.documentId ? code.locations[codeStr(i)] : nullLocation;
var location = code.documentId ? debugData.states[i].solidity : nullLocation;
if (location.start !== prevLocation.start || location.end !== prevLocation.end || code.documentId !== prevLocation.documentId)
{
prevLocation = { start: location.start, end: location.end, documentId: code.documentId, state: i };
@ -65,6 +64,7 @@ function initLocations()
locationMap[i] = locations.length - 1;
}
locations.push({ start: -1, end: -1, documentId: code.documentId, state: i });
locationMap[debugData.states.length - 1] = locations.length - 1;
}
@ -93,12 +93,10 @@ function initSlider()
function setupInstructions(stateIndex)
{
var instructions = debugData.states[stateIndex].code.instructions;
codeMap = {};
statesList.model.clear();
for (var i = 0; i < instructions.length; i++) {
for (var i = 0; i < instructions.length; i++)
statesList.model.append(instructions[i]);
codeMap[instructions[i].processIndex] = i;
}
callDataDump.listModel = debugData.states[stateIndex].callData.items;
}
@ -129,14 +127,14 @@ function display(stateIndex)
setupInstructions(stateIndex);
if (debugData.states[stateIndex].dataIndex !== debugData.states[currentDisplayedState].dataIndex)
setupCallData(stateIndex);
var codeLine = codeStr(stateIndex);
var state = debugData.states[stateIndex];
var codeLine = state.instructionIndex;
highlightSelection(codeLine);
completeCtxInformation(state);
currentDisplayedState = stateIndex;
var docId = debugData.states[stateIndex].code.documentId;
if (docId)
debugExecuteLocation(docId, locations[locationMap[stateIndex]]);
debugExecuteLocation(docId, debugData.states[stateIndex].solidity);
}
function displayFrame(frameIndex)
@ -183,12 +181,6 @@ function selectState(stateIndex)
statesSlider.value = stateIndex;
}
function codeStr(stateIndex)
{
var state = debugData.states[stateIndex];
return codeMap[state.curPC];
}
function highlightSelection(index)
{
statesList.positionViewAtRow(index, ListView.Center);
@ -206,6 +198,15 @@ function completeCtxInformation(state)
stack.listModel = state.debugStack;
storage.listModel = state.debugStorage;
memoryDump.listModel = state.debugMemory;
if (state.solidity) {
solLocals.listModel = state.solidity.locals;
solStorage.listModel = state.solidity.storage;
solCallStack.listModel = state.solidity.callStack;
} else {
solLocals.listModel = [];
solStorage.listModel = [];
solCallStack.listModel = [];
}
}
function isCallInstruction(index)
@ -229,7 +230,7 @@ function breakpointHit(i)
{
var bpLocations = breakpoints[debugData.states[i].code.documentId];
if (bpLocations) {
var location = locations[locationMap[i]];
var location = debugData.states[i].solidity;
if (location.start >= 0 && location.end >= location.start)
for (var b = 0; b < bpLocations.length; b++)
if (locationsIntersect(location, bpLocations[b]))

2
mix/res.qrc

@ -103,6 +103,8 @@
<file>qml/img/available_updates.png</file>
<file>qml/DeploymentDialog.qml</file>
<file>qml/img/search_filled.png</file>
<file>qml/StorageView.qml</file>
<file>qml/CallStack.qml</file>
<file>qml/img/help.png</file>
<file>qml/img/openedfolder.png</file>
<file>qml/img/b64.png</file>

Loading…
Cancel
Save