Skip to content
This repository has been archived by the owner on Mar 3, 2021. It is now read-only.

Add comments in Internal call tree #1290

Merged
merged 2 commits into from
Sep 11, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion remix-debug/src/solidity-decoder/internalCallTree.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class InternalCallTree {
if (!this.solidityProxy.loaded()) {
this.event.trigger('callTreeBuildFailed', ['compilation result not loaded. Cannot build internal call tree'])
} else {
// each recursive call to buildTree represent a new context (either call, delegatecall, internal function)
buildTree(this, 0, '', true).then((result) => {
if (result.error) {
this.event.trigger('callTreeBuildFailed', [result.error])
Expand All @@ -55,7 +56,9 @@ class InternalCallTree {
*/
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 = {}
/*
Expand Down Expand Up @@ -151,6 +154,7 @@ async function buildTree (tree, step, scopeId, isExternalCall) {
return { outStep: step, error: 'InternalCallTree - No source Location. ' + step }
}
var isCallInstruction = traceHelper.isCallInstruction(tree.traceManager.trace[step])
// we are checking if we are jumping in a new CALL or in an internal function
if (isCallInstruction || sourceLocation.jump === 'i') {
try {
var externalCallResult = await buildTree(tree, step + 1, scopeId === '' ? subScope.toString() : scopeId + '.' + subScope, isCallInstruction)
Expand All @@ -164,9 +168,12 @@ async function buildTree (tree, step, scopeId, isExternalCall) {
return { outStep: step, error: 'InternalCallTree - ' + e.message }
}
} 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
return { outStep: step + 1 }
} 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) {
includeVariableDeclaration(tree, step, sourceLocation, scopeId, newLocation, previousSourceLocation)
}
Expand All @@ -177,20 +184,27 @@ async function buildTree (tree, step, scopeId, isExternalCall) {
return { outStep: step }
}

// the reduced trace contain an entry only if that correspond to a new source location
function createReducedTrace (tree, index) {
tree.reducedTrace.push(index)
}

function includeVariableDeclaration (tree, step, sourceLocation, scopeId, newLocation, previousSourceLocation) {
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]) {
tree.traceManager.getStackAt(step, (error, stack) => {
// the stack length at this point is where the value of the new local variable will be stored.
// so, either this is the direct value, or the offset in memory. That depends on the type.
if (!error) {
tree.solidityProxy.contractNameAt(step, (error, contractName) => { // cached
if (!error) {
var states = tree.solidityProxy.extractStatesDefinitions()
var location = typesUtil.extractLocationFromAstVariable(variableDeclaration)
location = location === 'default' ? 'storage' : location
// we push the new local variable in our tree
tree.scopes[scopeId].locals[variableDeclaration.attributes.name] = {
name: variableDeclaration.attributes.name,
type: decodeInfo.parseType(variableDeclaration.attributes.type, states, contractName, location),
Expand All @@ -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)
if (functionDefinition && (newLocation && traceHelper.isJumpDestInstruction(tree.traceManager.trace[step - 1]) || functionDefinition.attributes.isConstructor)) {
tree.functionCallStack.push(step)
Expand All @@ -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) {
if (!tree.variableDeclarationByFile[sourceLocation.file]) {
var ast = tree.solidityProxy.ast(sourceLocation)
Expand All @@ -236,6 +254,8 @@ function resolveVariableDeclaration (tree, step, sourceLocation) {
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) {
if (!tree.functionDefinitionByFile[sourceLocation.file]) {
var ast = tree.solidityProxy.ast(sourceLocation)
Expand Down