add comment in Internal call tree

pull/5370/head
yann300 5 years ago
parent 3ffee92cd3
commit 44638e974c
  1. 22
      remix-debug/src/solidity-decoder/internalCallTree.js

@ -34,6 +34,7 @@ class InternalCallTree {
if (!this.solidityProxy.loaded()) { if (!this.solidityProxy.loaded()) {
this.event.trigger('callTreeBuildFailed', ['compilation result not loaded. Cannot build internal call tree']) this.event.trigger('callTreeBuildFailed', ['compilation result not loaded. Cannot build internal call tree'])
} else { } else {
// each recursive call to buildTree represent a new context (either call, delegatecall, internal function)
buildTree(this, 0, '', true).then((result) => { buildTree(this, 0, '', true).then((result) => {
if (result.error) { if (result.error) {
this.event.trigger('callTreeBuildFailed', [result.error]) this.event.trigger('callTreeBuildFailed', [result.error])
@ -55,7 +56,9 @@ class InternalCallTree {
*/ */
reset () { reset () {
/* /*
scopes: map of scopes defined by range in the vmtrace {firstStep, lastStep, locals}. Keys represent the level of deepness (scopeId) scopes: map of scopes defined by range in the vmtrace {firstStep, lastStep, locals}.
Keys represent the level of deepness (scopeId)
scopeId : <currentscope_id>.<sub_scope_id>.<sub_sub_scope_id>
*/ */
this.scopes = {} this.scopes = {}
/* /*
@ -151,6 +154,7 @@ async function buildTree (tree, step, scopeId, isExternalCall) {
return { outStep: step, error: 'InternalCallTree - No source Location. ' + step } return { outStep: step, error: 'InternalCallTree - No source Location. ' + step }
} }
var isCallInstruction = traceHelper.isCallInstruction(tree.traceManager.trace[step]) var isCallInstruction = traceHelper.isCallInstruction(tree.traceManager.trace[step])
// we are checking if we jumping in a new CALL or in an internal function
if (isCallInstruction || sourceLocation.jump === 'i') { if (isCallInstruction || sourceLocation.jump === 'i') {
try { try {
var externalCallResult = await buildTree(tree, step + 1, scopeId === '' ? subScope.toString() : scopeId + '.' + subScope, isCallInstruction) var externalCallResult = await buildTree(tree, step + 1, scopeId === '' ? subScope.toString() : scopeId + '.' + subScope, isCallInstruction)
@ -164,9 +168,12 @@ async function buildTree (tree, step, scopeId, isExternalCall) {
return { outStep: step, error: 'InternalCallTree - ' + e.message } return { outStep: step, error: 'InternalCallTree - ' + e.message }
} }
} else if ((isExternalCall && callDepthChange(step, tree.traceManager.trace)) || (!isExternalCall && sourceLocation.jump === 'o')) { } else if ((isExternalCall && callDepthChange(step, tree.traceManager.trace)) || (!isExternalCall && sourceLocation.jump === 'o')) {
// if not, we might be returning from a CALL or internal function. This is what is checked here.
tree.scopes[scopeId].lastStep = step tree.scopes[scopeId].lastStep = step
return { outStep: step + 1 } return { outStep: step + 1 }
} else { } else {
// if not, we are in the current scope.
// We check in `includeVariableDeclaration` if there is a new local variable in scope for this specific `step`
if (tree.includeLocalVariables) { if (tree.includeLocalVariables) {
includeVariableDeclaration(tree, step, sourceLocation, scopeId, newLocation, previousSourceLocation) includeVariableDeclaration(tree, step, sourceLocation, scopeId, newLocation, previousSourceLocation)
} }
@ -177,20 +184,27 @@ async function buildTree (tree, step, scopeId, isExternalCall) {
return { outStep: step } return { outStep: step }
} }
// the reduced trace contain an entry only if that correspond to a new source location
function createReducedTrace (tree, index) { function createReducedTrace (tree, index) {
tree.reducedTrace.push(index) tree.reducedTrace.push(index)
} }
function includeVariableDeclaration (tree, step, sourceLocation, scopeId, newLocation, previousSourceLocation) { function includeVariableDeclaration (tree, step, sourceLocation, scopeId, newLocation, previousSourceLocation) {
var variableDeclaration = resolveVariableDeclaration(tree, step, sourceLocation) var variableDeclaration = resolveVariableDeclaration(tree, step, sourceLocation)
// using the vm trace step, the current source location and the ast,
// we check if the current vm trace step target a new ast node of type VariableDeclaration
// that way we know that there is a new local variable from here.
if (variableDeclaration && !tree.scopes[scopeId].locals[variableDeclaration.attributes.name]) { if (variableDeclaration && !tree.scopes[scopeId].locals[variableDeclaration.attributes.name]) {
tree.traceManager.getStackAt(step, (error, stack) => { tree.traceManager.getStackAt(step, (error, stack) => {
// the stack length at this point is where the value of the new local will be stored.
// so, either this is the direct value, or the offset in memory. That depends on the type.
if (!error) { if (!error) {
tree.solidityProxy.contractNameAt(step, (error, contractName) => { // cached tree.solidityProxy.contractNameAt(step, (error, contractName) => { // cached
if (!error) { if (!error) {
var states = tree.solidityProxy.extractStatesDefinitions() var states = tree.solidityProxy.extractStatesDefinitions()
var location = typesUtil.extractLocationFromAstVariable(variableDeclaration) var location = typesUtil.extractLocationFromAstVariable(variableDeclaration)
location = location === 'default' ? 'storage' : location location = location === 'default' ? 'storage' : location
// we push the new local variable in our tree
tree.scopes[scopeId].locals[variableDeclaration.attributes.name] = { tree.scopes[scopeId].locals[variableDeclaration.attributes.name] = {
name: variableDeclaration.attributes.name, name: variableDeclaration.attributes.name,
type: decodeInfo.parseType(variableDeclaration.attributes.type, states, contractName, location), type: decodeInfo.parseType(variableDeclaration.attributes.type, states, contractName, location),
@ -202,6 +216,8 @@ function includeVariableDeclaration (tree, step, sourceLocation, scopeId, newLoc
} }
}) })
} }
// we check here if we are at the beginning inside a new function.
// if that is the case, we have to add to locals tree the inputs and output params
var functionDefinition = resolveFunctionDefinition(tree, step, previousSourceLocation) var functionDefinition = resolveFunctionDefinition(tree, step, previousSourceLocation)
if (functionDefinition && (newLocation && traceHelper.isJumpDestInstruction(tree.traceManager.trace[step - 1]) || functionDefinition.attributes.isConstructor)) { if (functionDefinition && (newLocation && traceHelper.isJumpDestInstruction(tree.traceManager.trace[step - 1]) || functionDefinition.attributes.isConstructor)) {
tree.functionCallStack.push(step) tree.functionCallStack.push(step)
@ -223,6 +239,8 @@ function includeVariableDeclaration (tree, step, sourceLocation, scopeId, newLoc
} }
} }
// this extract all the variable declaration for a given ast and file
// and keep this in a cache
function resolveVariableDeclaration (tree, step, sourceLocation) { function resolveVariableDeclaration (tree, step, sourceLocation) {
if (!tree.variableDeclarationByFile[sourceLocation.file]) { if (!tree.variableDeclarationByFile[sourceLocation.file]) {
var ast = tree.solidityProxy.ast(sourceLocation) var ast = tree.solidityProxy.ast(sourceLocation)
@ -236,6 +254,8 @@ function resolveVariableDeclaration (tree, step, sourceLocation) {
return tree.variableDeclarationByFile[sourceLocation.file][sourceLocation.start + ':' + sourceLocation.length + ':' + sourceLocation.file] return tree.variableDeclarationByFile[sourceLocation.file][sourceLocation.start + ':' + sourceLocation.length + ':' + sourceLocation.file]
} }
// this extract all the function definition for a given ast and file
// and keep this in a cache
function resolveFunctionDefinition (tree, step, sourceLocation) { function resolveFunctionDefinition (tree, step, sourceLocation) {
if (!tree.functionDefinitionByFile[sourceLocation.file]) { if (!tree.functionDefinitionByFile[sourceLocation.file]) {
var ast = tree.solidityProxy.ast(sourceLocation) var ast = tree.solidityProxy.ast(sourceLocation)

Loading…
Cancel
Save