add InternalCallTree

pull/7/head
yann300 8 years ago
parent c0121f7cf0
commit 12f18f865c
  1. 12
      src/ui/Ethdebugger.js
  2. 5
      src/ui/VmDebugger.js
  3. 139
      src/util/internalCallTree.js
  4. 11
      test/solidity/contracts/intLocal.js
  5. 53
      test/solidity/localDecoder.js

@ -11,10 +11,11 @@ var ui = require('../helpers/ui')
var Web3Providers = require('../web3Provider/web3Providers')
var DummyProvider = require('../web3Provider/dummyProvider')
var CodeManager = require('../code/codeManager')
var LocalDecoder = require('../solidity/localDecoder')
var SolidityProxy = require('../solidity/solidityProxy')
var InternalCallTree = require('../util/internalCallTree')
function Ethdebugger () {
var self = this
this.event = new EventManager()
this.currentStepIndex = -1
@ -28,8 +29,9 @@ function Ethdebugger () {
this.traceManager = new TraceManager()
this.codeManager = new CodeManager(this.traceManager)
this.solidityProxy = new SolidityProxy(this.traceManager, this.codeManager)
this.locals = new LocalDecoder(this.codeManager, this.traceManager.traceAnalyser.event, this.solidityProxy)
var self = this
var callTree = new InternalCallTree(this.event, this.traceManager, this.solidityProxy, this.codeManager)
this.event.register('indexChanged', this, function (index) {
self.codeManager.resolveStep(index, self.tx)
})
@ -48,7 +50,7 @@ function Ethdebugger () {
this.stepManager.event.register('stepChanged', this, function (stepIndex) {
self.stepChanged(stepIndex)
})
this.vmDebugger = new VmDebugger(this, this.traceManager, this.codeManager, this.solidityProxy)
this.vmDebugger = new VmDebugger(this, this.traceManager, this.codeManager, this.solidityProxy, callTree)
}
Ethdebugger.prototype.web3 = function () {
@ -129,7 +131,7 @@ Ethdebugger.prototype.startDebugging = function (blockNumber, txIndex, tx) {
if (result) {
self.statusMessage = ''
yo.update(self.view, self.render())
self.event.trigger('newTraceLoaded')
self.event.trigger('newTraceLoaded', [self.traceManager.trace])
} else {
self.statusMessage = error
yo.update(self.view, self.render())

@ -9,9 +9,10 @@ var FullStoragesChangesPanel = require('./FullStoragesChanges')
var StepDetail = require('./StepDetail')
var DropdownPanel = require('./DropdownPanel')
var SolidityState = require('./SolidityState')
var SolidityLocals = require('./SolidityLocals')
var yo = require('yo-yo')
function VmDebugger (_parent, _traceManager, _codeManager, _solidityProxy) {
function VmDebugger (_parent, _traceManager, _codeManager, _solidityProxy, _callTree) {
this.asmCode = new CodeListView(_parent, _codeManager)
this.stackPanel = new StackPanel(_parent, _traceManager)
this.storagePanel = new StoragePanel(_parent, _traceManager)
@ -20,6 +21,7 @@ function VmDebugger (_parent, _traceManager, _codeManager, _solidityProxy) {
this.callstackPanel = new CallstackPanel(_parent, _traceManager)
this.stepDetail = new StepDetail(_parent, _traceManager)
this.solidityState = new SolidityState(_parent, _traceManager, _codeManager, _solidityProxy)
this.solidityLocals = new SolidityLocals(_parent, _traceManager, _callTree)
/* Return values - */
this.returnValuesPanel = new DropdownPanel('Return Value')
@ -53,6 +55,7 @@ VmDebugger.prototype.render = function () {
var view = yo`<div id='vmdebugger' style='display:none'>
<div>
${this.asmCode.render()}
${this.solidityLocals.render()}
${this.solidityState.render()}
${this.stepDetail.render()}
${this.stackPanel.render()}

@ -0,0 +1,139 @@
'use strict'
var SourceLocationTracker = require('../code/sourceLocationTracker')
var AstWalker = require('./astWalker')
var EventManager = require('../lib/eventManager')
var decodeInfo = require('../solidity/decodeInfo')
var util = require('../helpers/util')
class InternalCallTree {
constructor (debuggerEvent, traceManager, solidityProxy, codeManager, opts) {
this.includeLocalsVariables = opts.includeLocalsVariables
this.event = new EventManager()
this.solidityProxy = solidityProxy
this.traceManager = traceManager
this.sourceLocationTracker = new SourceLocationTracker(codeManager)
debuggerEvent.register('newTraceLoaded', (trace) => {
this.reset()
this.buildTree(trace)
this.event.trigger('callTreeReady', [this.scopes, this.scopeStarts])
})
}
buildTree (trace) {
buildTree(this, 0, '', trace)
}
reset () {
this.scopes = {}
this.scopeStarts = {}
this.variableDeclarationByFile = {}
this.astWalker = new AstWalker()
}
findScope (vmtraceIndex) {
var scopeId = util.findLowerBoundValue(vmtraceIndex, Object.keys(this.scopeStarts))
var scopes = this.scopes[scopeId]
var reg = /(.\d)$/
while (scopes.lastStep < vmtraceIndex) {
scopeId = scopeId.match(reg)
scopes = this.scopes[scopeId[1]]
}
return scopes
}
}
function buildTree (tree, step, scopeId, trace) {
let subScope = 1
tree.scopeStarts[step] = scopeId
tree.scopes[scopeId] = { firstStep: step }
while (step < trace.length) {
var sourceLocation
extractSourceLocation(tree, step, (error, src) => {
if (error) {
console.log(error)
} else {
sourceLocation = src
}
})
if (sourceLocation.jump === 'i') {
step = buildTree(tree, step + 1, scopeId === '' ? subScope.toString() : scopeId + '.' + subScope, trace)
subScope++
} else if (sourceLocation.jump === 'o') {
tree.scopes[scopeId].lastStep = step
return step + 1
} else {
if (tree.includeLocalsVariables) {
var variableDeclaration = resolveVariableDeclaration(tree, step, sourceLocation)
if (variableDeclaration) {
if (!tree.scopes[scopeId].locals) {
tree.scopes[scopeId].locals = {}
}
tree.traceManager.getStackAt(step, (error, stack) => {
if (!error) {
tree.solidityProxy.contractNameAt(step, (error, contractName) => { // cached
if (!error) {
tree.solidityProxy.extractStateVariablesAt(step, (error, stateVars) => { // cached
if (!error) {
tree.scopes[scopeId].locals[variableDeclaration.attributes.name] = {
name: variableDeclaration.attributes.name,
type: decodeInfo.parseType(variableDeclaration.attributes.type, contractName, stateVars),
stackHeight: stack.length
}
}
})
}
})
}
})
}
}
step++
}
}
}
function extractSourceLocation (tree, step, cb) {
tree.traceManager.getCurrentCalledAddressAt(step, (error, address) => {
if (!error) {
tree.sourceLocationTracker.getSourceLocationFromVMTraceIndex(address, step, tree.solidityProxy.contracts, (error, sourceLocation) => {
if (!error) {
cb(null, sourceLocation)
} else {
cb('InternalCallTree - Cannot retrieve sourcelocation for step ' + step)
}
})
} else {
cb('InternalCallTree - Cannot retrieve address for step ' + step)
}
})
}
function resolveVariableDeclaration (tree, step, sourceLocation) {
if (!tree.variableDeclarationByFile[sourceLocation.file]) {
tree.variableDeclarationByFile[sourceLocation.file] = extractVariableDeclarations(tree.solidityProxy.ast(sourceLocation), tree.astWalker)
}
var variableDeclarations = tree.variableDeclarationByFile[sourceLocation.file]
var ret = null
tree.solidityProxy.extractStateVariablesAt(step, (error, stateVars) => { // cached
if (error) {
console.log(error)
} else {
ret = variableDeclarations[sourceLocation.start + ':' + sourceLocation.length + ':' + sourceLocation.file]
}
})
return ret
}
function extractVariableDeclarations (ast, astWalker) {
var ret = {}
astWalker.walk(ast, (node) => {
if (node.name === 'VariableDeclaration') {
ret[node.src] = node
}
return true
})
return ret
}
module.exports = InternalCallTree

@ -19,6 +19,17 @@ module.exports = {
int256 i256 = 3434343;
int i = -32432423423;
int32 ishrink = 2;
level11();
level12();
level11();
}
function level11() {
uint8 ui8 = 123;
level12();
}
function level12() {
uint8 ui81 = 12;
}
}
`}

@ -12,8 +12,9 @@ var utileth = require('ethereumjs-util')
var Web3Providers = require('../../src/web3Provider/web3Providers')
var traceHelper = require('../../src/helpers/traceHelper')
var util = require('../../src/helpers/global')
var LocalDecoder = require('../../src/solidity/localDecoder')
var SolidityProxy = require('../../src/solidity/solidityProxy')
var InternalCallTree = require('../../src/util/internalCallTree')
var EventManager = require('../../src/lib/eventManager')
tape('solidity', function (t) {
t.test('local decoder', function (st) {
@ -35,27 +36,41 @@ tape('solidity', function (t) {
var codeManager = new CodeManager(traceManager)
var solidityProxy = new SolidityProxy(traceManager, codeManager)
solidityProxy.reset(output)
var localDecoder = new LocalDecoder(codeManager, traceManager.traceAnalyser.event, solidityProxy)
traceManager.resolveTrace(tx, function (error, result) {
var debuggerEvent = new EventManager()
var callTree = new InternalCallTree(debuggerEvent, traceManager, solidityProxy, codeManager, { includeLocalsVariables: true })
callTree.event.register('callTreeReady', (scopes, scopeStarts) => {
st.equals(scopeStarts[0], '')
st.equals(scopeStarts[77], '1')
st.equals(scopeStarts[92], '1.1')
st.equals(scopeStarts[115], '2')
st.equals(scopeStarts[134], '3')
st.equals(scopeStarts[149], '3.1')
st.equals(scopes[''].locals['ui8'].type.typeName, 'uint')
st.equals(scopes[''].locals['ui16'].type.typeName, 'uint')
st.equals(scopes[''].locals['ui32'].type.typeName, 'uint')
st.equals(scopes[''].locals['ui64'].type.typeName, 'uint')
st.equals(scopes[''].locals['ui128'].type.typeName, 'uint')
st.equals(scopes[''].locals['ui256'].type.typeName, 'uint')
st.equals(scopes[''].locals['ui'].type.typeName, 'uint')
st.equals(scopes[''].locals['i8'].type.typeName, 'int')
st.equals(scopes[''].locals['i16'].type.typeName, 'int')
st.equals(scopes[''].locals['i32'].type.typeName, 'int')
st.equals(scopes[''].locals['i64'].type.typeName, 'int')
st.equals(scopes[''].locals['i128'].type.typeName, 'int')
st.equals(scopes[''].locals['i256'].type.typeName, 'int')
st.equals(scopes[''].locals['i'].type.typeName, 'int')
st.equals(scopes[''].locals['ishrink'].type.typeName, 'int')
st.equals(scopes['1'].locals['ui8'].type.typeName, 'uint')
st.equals(scopes['1.1'].locals['ui81'].type.typeName, 'uint')
st.equals(scopes['2'].locals['ui81'].type.typeName, 'uint')
st.equals(scopes['3'].locals['ui8'].type.typeName, 'uint')
st.equals(scopes['3.1'].locals['ui81'].type.typeName, 'uint')
})
traceManager.resolveTrace(tx, (error, result) => {
if (error) {
st.fail(error)
} else {
var locals = localDecoder.locals
st.equals(locals['ui8'].type.typeName, 'uint')
st.equals(locals['ui16'].type.typeName, 'uint')
st.equals(locals['ui32'].type.typeName, 'uint')
st.equals(locals['ui64'].type.typeName, 'uint')
st.equals(locals['ui128'].type.typeName, 'uint')
st.equals(locals['ui256'].type.typeName, 'uint')
st.equals(locals['ui'].type.typeName, 'uint')
st.equals(locals['i8'].type.typeName, 'int')
st.equals(locals['i16'].type.typeName, 'int')
st.equals(locals['i32'].type.typeName, 'int')
st.equals(locals['i64'].type.typeName, 'int')
st.equals(locals['i128'].type.typeName, 'int')
st.equals(locals['i256'].type.typeName, 'int')
st.equals(locals['i'].type.typeName, 'int')
st.equals(locals['ishrink'].type.typeName, 'int')
debuggerEvent.trigger('newTraceLoaded', [traceManager.trace])
}
})
}

Loading…
Cancel
Save