parent
0e270ffbcf
commit
9a30bb5b2e
@ -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 |
Loading…
Reference in new issue