|
|
|
//debugData => contain all debug states.
|
|
|
|
//statesList => ListView
|
|
|
|
|
|
|
|
var currentSelectedState = null;
|
|
|
|
var currentDisplayedState = null;
|
|
|
|
var debugData = null;
|
|
|
|
var locations = [];
|
|
|
|
var locationMap = {};
|
|
|
|
var breakpoints = {};
|
|
|
|
|
|
|
|
function init(data)
|
|
|
|
{
|
|
|
|
jumpOutBackAction.enabled(false);
|
|
|
|
jumpIntoBackAction.enabled(false);
|
|
|
|
jumpIntoForwardAction.enabled(false);
|
|
|
|
jumpOutForwardAction.enabled(false);
|
|
|
|
jumpOverBackAction.enabled(false);
|
|
|
|
jumpOverForwardAction.enabled(false);
|
|
|
|
|
|
|
|
if (data === null) {
|
|
|
|
statesList.model.clear();
|
|
|
|
statesSlider.maximumValue = 0;
|
|
|
|
statesSlider.value = 0;
|
|
|
|
currentSelectedState = null;
|
|
|
|
currentDisplayedState = null;
|
|
|
|
debugData = null;
|
|
|
|
locations = [];
|
|
|
|
locationMap = {};
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
debugData = data;
|
|
|
|
currentSelectedState = 0;
|
|
|
|
currentDisplayedState = 0;
|
|
|
|
setupInstructions(currentSelectedState);
|
|
|
|
setupCallData(currentSelectedState);
|
|
|
|
initLocations();
|
|
|
|
initSlider();
|
|
|
|
selectState(currentSelectedState);
|
|
|
|
}
|
|
|
|
|
|
|
|
function updateMode()
|
|
|
|
{
|
|
|
|
initSlider();
|
|
|
|
}
|
|
|
|
|
|
|
|
function initLocations()
|
|
|
|
{
|
|
|
|
locations = [];
|
|
|
|
if (debugData.states.length === 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
var nullLocation = { start: -1, end: -1, documentId: "", state: 0 };
|
|
|
|
var prevLocation = nullLocation;
|
|
|
|
|
|
|
|
for (var i = 0; i < debugData.states.length - 1; i++) {
|
|
|
|
var code = debugData.states[i].code;
|
|
|
|
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 };
|
|
|
|
locations.push(prevLocation);
|
|
|
|
}
|
|
|
|
locationMap[i] = locations.length - 1;
|
|
|
|
}
|
|
|
|
locations.push({ start: -1, end: -1, documentId: code.documentId, state: i });
|
|
|
|
|
|
|
|
locationMap[debugData.states.length - 1] = locations.length - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
function setBreakpoints(bp)
|
|
|
|
{
|
|
|
|
breakpoints = bp;
|
|
|
|
}
|
|
|
|
|
|
|
|
function srcMode()
|
|
|
|
{
|
|
|
|
return !assemblyMode && locations.length;
|
|
|
|
}
|
|
|
|
|
|
|
|
function initSlider()
|
|
|
|
{
|
|
|
|
if (!debugData)
|
|
|
|
statesSlider.maximumValue = 0;
|
|
|
|
else if (srcMode()) {
|
|
|
|
statesSlider.maximumValue = locations.length - 1;
|
|
|
|
} else {
|
|
|
|
statesSlider.maximumValue = debugData.states.length - 1;
|
|
|
|
}
|
|
|
|
statesSlider.value = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function setupInstructions(stateIndex)
|
|
|
|
{
|
|
|
|
var instructions = debugData.states[stateIndex].code.instructions;
|
|
|
|
statesList.model.clear();
|
|
|
|
for (var i = 0; i < instructions.length; i++)
|
|
|
|
statesList.model.append(instructions[i]);
|
|
|
|
|
|
|
|
callDataDump.listModel = debugData.states[stateIndex].callData.items;
|
|
|
|
}
|
|
|
|
|
|
|
|
function setupCallData(stateIndex)
|
|
|
|
{
|
|
|
|
callDataDump.listModel = debugData.states[stateIndex].callData.items;
|
|
|
|
}
|
|
|
|
|
|
|
|
function moveSelection(incr)
|
|
|
|
{
|
|
|
|
if (srcMode()) {
|
|
|
|
var locationIndex = locationMap[currentSelectedState];
|
|
|
|
if (locationIndex + incr >= 0 && locationIndex + incr < locations.length)
|
|
|
|
selectState(locations[locationIndex + incr].state);
|
|
|
|
} else {
|
|
|
|
if (currentSelectedState + incr >= 0 && currentSelectedState + incr < debugData.states.length)
|
|
|
|
selectState(currentSelectedState + incr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function display(stateIndex)
|
|
|
|
{
|
|
|
|
if (stateIndex < 0)
|
|
|
|
stateIndex = 0;
|
|
|
|
if (stateIndex >= debugData.states.length)
|
|
|
|
stateIndex = debugData.states.length - 1;
|
|
|
|
if (debugData.states[stateIndex].codeIndex !== debugData.states[currentDisplayedState].codeIndex)
|
|
|
|
setupInstructions(stateIndex);
|
|
|
|
if (debugData.states[stateIndex].dataIndex !== debugData.states[currentDisplayedState].dataIndex)
|
|
|
|
setupCallData(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, debugData.states[stateIndex].solidity);
|
|
|
|
}
|
|
|
|
|
|
|
|
function displayFrame(frameIndex)
|
|
|
|
{
|
|
|
|
var state = debugData.states[currentSelectedState];
|
|
|
|
if (frameIndex === 0)
|
|
|
|
display(currentSelectedState);
|
|
|
|
else
|
|
|
|
display(state.levels[frameIndex - 1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
function select(index)
|
|
|
|
{
|
|
|
|
if (srcMode())
|
|
|
|
selectState(locations[index].state);
|
|
|
|
else
|
|
|
|
selectState(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
function selectState(stateIndex)
|
|
|
|
{
|
|
|
|
display(stateIndex);
|
|
|
|
currentSelectedState = stateIndex;
|
|
|
|
var state = debugData.states[stateIndex];
|
|
|
|
jumpIntoForwardAction.enabled(stateIndex < debugData.states.length - 1)
|
|
|
|
jumpIntoBackAction.enabled(stateIndex > 0);
|
|
|
|
jumpOverForwardAction.enabled(stateIndex < debugData.states.length - 1);
|
|
|
|
jumpOverBackAction.enabled(stateIndex > 0);
|
|
|
|
jumpOutBackAction.enabled(state.levels.length > 1);
|
|
|
|
jumpOutForwardAction.enabled(state.levels.length > 1);
|
|
|
|
runForwardAction.enabled(stateIndex < debugData.states.length - 1)
|
|
|
|
runBackAction.enabled(stateIndex > 0);
|
|
|
|
|
|
|
|
var callStackData = [];
|
|
|
|
for (var l = 0; l < state.levels.length; l++) {
|
|
|
|
var address = debugData.states[state.levels[l] + 1].code.address;
|
|
|
|
callStackData.push(address);
|
|
|
|
}
|
|
|
|
callStackData.push(debugData.states[0].code.address);
|
|
|
|
callStack.listModel = callStackData;
|
|
|
|
if (srcMode())
|
|
|
|
statesSlider.value = locationMap[stateIndex];
|
|
|
|
else
|
|
|
|
statesSlider.value = stateIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
function highlightSelection(index)
|
|
|
|
{
|
|
|
|
statesList.positionViewAtRow(index, ListView.Center);
|
|
|
|
statesList.selection.clear();
|
|
|
|
statesList.selection.select(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
function completeCtxInformation(state)
|
|
|
|
{
|
|
|
|
currentStep.update(state.step);
|
|
|
|
mem.update(state.newMemSize.value() + " " + qsTr("words"));
|
|
|
|
stepCost.update(state.gasCost.value());
|
|
|
|
gasSpent.update(debugData.states[0].gas.subtract(state.gas).value());
|
|
|
|
|
|
|
|
stack.listModel = state.debugStack;
|
|
|
|
storage.listModel = state.debugStorage;
|
|
|
|
memoryDump.listModel = state.debugMemory;
|
|
|
|
if (state.solidity) {
|
|
|
|
solLocals.setData(state.solidity.locals.variables, state.solidity.locals.values);
|
|
|
|
solStorage.setData(state.solidity.storage.variables, state.solidity.storage.values);
|
|
|
|
solCallStack.listModel = state.solidity.callStack;
|
|
|
|
} else {
|
|
|
|
solLocals.setData([], {});
|
|
|
|
solStorage.setData([], {});
|
|
|
|
solCallStack.listModel = [];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function isCallInstruction(index)
|
|
|
|
{
|
|
|
|
var state = debugData.states[index];
|
|
|
|
return state.instruction === "CALL" || state.instruction === "CREATE";
|
|
|
|
}
|
|
|
|
|
|
|
|
function isReturnInstruction(index)
|
|
|
|
{
|
|
|
|
var state = debugData.states[index];
|
|
|
|
return state.instruction === "RETURN"
|
|
|
|
}
|
|
|
|
|
|
|
|
function locationsIntersect(l1, l2)
|
|
|
|
{
|
|
|
|
return l1.start <= l2.end && l1.end >= l2.start;
|
|
|
|
}
|
|
|
|
|
|
|
|
function breakpointHit(i)
|
|
|
|
{
|
|
|
|
var bpLocations = breakpoints[debugData.states[i].code.documentId];
|
|
|
|
if (bpLocations) {
|
|
|
|
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]))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
function stepIntoBack()
|
|
|
|
{
|
|
|
|
moveSelection(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
function stepOverBack()
|
|
|
|
{
|
|
|
|
if (currentSelectedState > 0 && isReturnInstruction(currentSelectedState - 1))
|
|
|
|
stepOutBack();
|
|
|
|
else
|
|
|
|
moveSelection(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
function stepOverForward()
|
|
|
|
{
|
|
|
|
if (isCallInstruction(currentSelectedState))
|
|
|
|
stepOutForward();
|
|
|
|
else
|
|
|
|
moveSelection(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
function stepIntoForward()
|
|
|
|
{
|
|
|
|
moveSelection(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
function runBack()
|
|
|
|
{
|
|
|
|
var i = currentSelectedState - 1;
|
|
|
|
while (i > 0 && !breakpointHit(i)) {
|
|
|
|
--i;
|
|
|
|
}
|
|
|
|
selectState(i);
|
|
|
|
}
|
|
|
|
|
|
|
|
function runForward()
|
|
|
|
{
|
|
|
|
var i = currentSelectedState + 1;
|
|
|
|
while (i < debugData.states.length - 1 && !breakpointHit(i)) {
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
selectState(i);
|
|
|
|
}
|
|
|
|
|
|
|
|
function stepOutBack()
|
|
|
|
{
|
|
|
|
var i = currentSelectedState - 1;
|
|
|
|
var depth = 0;
|
|
|
|
while (--i >= 0) {
|
|
|
|
if (breakpointHit(i))
|
|
|
|
break;
|
|
|
|
if (isCallInstruction(i))
|
|
|
|
if (depth == 0)
|
|
|
|
break;
|
|
|
|
else depth--;
|
|
|
|
else if (isReturnInstruction(i))
|
|
|
|
depth++;
|
|
|
|
}
|
|
|
|
selectState(i);
|
|
|
|
}
|
|
|
|
|
|
|
|
function stepOutForward()
|
|
|
|
{
|
|
|
|
var i = currentSelectedState;
|
|
|
|
var depth = 0;
|
|
|
|
while (++i < debugData.states.length) {
|
|
|
|
if (breakpointHit(i))
|
|
|
|
break;
|
|
|
|
if (isReturnInstruction(i))
|
|
|
|
if (depth == 0)
|
|
|
|
break;
|
|
|
|
else
|
|
|
|
depth--;
|
|
|
|
else if (isCallInstruction(i))
|
|
|
|
depth++;
|
|
|
|
}
|
|
|
|
selectState(i + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
function jumpTo(value)
|
|
|
|
{
|
|
|
|
select(value);
|
|
|
|
}
|