- functionFromPC

- functionFromStep
pull/7/head
yann300 8 years ago
parent 0ea03645e4
commit 51a34de0a0
  1. 3
      package.json
  2. 103
      src/code/codeManager.js
  3. 114
      src/util/sourceMappingDecoder.js
  4. 31
      test/sourceMappingDecoder.js
  5. 1
      test/tests.js

@ -29,7 +29,8 @@
"tape": "^4.6.0",
"web3": "^0.15.3",
"yo-yo": "^1.2.1",
"yo-yoify": "^3.1.0"
"yo-yoify": "^3.1.0",
"solc": "^0.4.3"
},
"scripts": {
"start_node": "./runNode.sh",

@ -2,13 +2,12 @@
var traceHelper = require('../helpers/traceHelper')
var codeResolver = require('./codeResolver')
var EventManager = require('../lib/eventManager')
var SourceMappingDecoder = require('../util/sourceMappingDecoder')
/*
resolve contract code referenced by vmtrace in order to be used by asm listview.
events:
- indexChanged: triggered when an item is selected
- codeChanged: triggered when an item (in a different context) is selected
- loadingCode: triggerred when loading new code
- changed: triggered when an item is selected
- resolvingStep: when CodeManager resolves code/selected instruction of a new step
*/
@ -19,34 +18,35 @@ function CodeManager (_traceManager) {
this.codeResolver = codeResolver
}
/**
* resolve the code of the given @arg stepIndex and trigger appropriate event
*
* @param {String} stepIndex - vm trace step
* @param {Object} tx - transaction (given by web3)
*/
CodeManager.prototype.resolveStep = function (stepIndex, tx) {
if (stepIndex < 0) return
this.event.trigger('resolvingStep')
var self = this
if (stepIndex === 0) {
self.retrieveCodeAndTrigger(tx.to, stepIndex, tx)
retrieveCodeAndTrigger(self, tx.to, stepIndex, tx)
} else {
this.traceManager.getCurrentCalledAddressAt(stepIndex, function (error, address) {
if (error) {
console.log(error)
} else {
self.retrieveCodeAndTrigger(address, stepIndex, tx)
retrieveCodeAndTrigger(self, address, stepIndex, tx)
}
})
}
}
CodeManager.prototype.retrieveCodeAndTrigger = function (address, stepIndex, tx) {
var self = this
this.getCode(address, function (error, result) {
if (!error) {
self.retrieveIndexAndTrigger(address, stepIndex, result.instructions)
} else {
console.log(error)
}
})
}
/**
* Retrieve the code located at the given @arg address
*
* @param {String} address - address of the contract to get the code from
* @param {Function} cb - callback function, return the bytecode
*/
CodeManager.prototype.getCode = function (address, cb) {
if (traceHelper.isContractCreation(address)) {
var codes = codeResolver.getExecutingCodeFromCache(address)
@ -67,27 +67,84 @@ CodeManager.prototype.getCode = function (address, cb) {
}
}
CodeManager.prototype.retrieveIndexAndTrigger = function (address, step, code) {
/**
* Retrieve the called function for the current vm step for the given @arg address
*
* @param {String} stepIndex - vm trace step
* @param {String} sourceMap - source map given byt the compilation result
* @param {Object} ast - ast given by the compilation result
* @return {Object} return the ast node of the function
*/
CodeManager.prototype.getFunctionFromStep = function (stepIndex, sourceMap, ast) {
var self = this
this.getInstructionIndex(address, step, function (error, result) {
if (!error) {
self.event.trigger('changed', [code, address, result])
} else {
this.traceManager.getCurrentCalledAddressAt(stepIndex, function (error, address) {
if (error) {
console.log(error)
return { error: 'Cannot retrieve current address for ' + stepIndex }
} else {
self.traceManager.getCurrentPC(stepIndex, function (error, pc) {
if (error) {
console.log(error)
return { error: 'Cannot retrieve current PC for ' + stepIndex }
} else {
return self.getFunctionFromPC(address, pc, sourceMap, ast)
}
})
}
})
}
/**
* Retrieve the instruction index of the given @arg step
*
* @param {String} address - address of the current context
* @param {String} step - vm trace step
* @param {Function} callback - instruction index
*/
CodeManager.prototype.getInstructionIndex = function (address, step, callback) {
this.traceManager.getCurrentPC(step, function (error, instIndex) {
this.traceManager.getCurrentPC(step, function (error, pc) {
if (error) {
console.log(error)
callback('Cannot retrieve current PC for ' + step, null)
} else {
var itemIndex = codeResolver.getInstructionIndex(address, instIndex)
var itemIndex = codeResolver.getInstructionIndex(address, pc)
callback(null, itemIndex)
}
})
}
/**
* Retrieve the called function for the given @arg pc and @arg address
*
* @param {String} address - address of the current context (used to resolve instruction index)
* @param {String} pc - pc that point to the instruction index
* @param {String} sourceMap - source map given byt the compilation result
* @param {Object} ast - ast given by the compilation result
* @return {Object} return the ast node of the function
*/
CodeManager.prototype.getFunctionFromPC = function (address, pc, sourceMap, ast) {
var instIndex = codeResolver.getInstructionIndex(address, pc)
return SourceMappingDecoder.findNodeAtInstructionIndex('FunctionDefinition', instIndex, sourceMap, ast)
}
function retrieveCodeAndTrigger (codeMananger, address, stepIndex, tx) {
codeMananger.getCode(address, function (error, result) {
if (!error) {
retrieveIndexAndTrigger(codeMananger, address, stepIndex, result.instructions)
} else {
console.log(error)
}
})
}
function retrieveIndexAndTrigger (codeMananger, address, step, code) {
codeMananger.getInstructionIndex(address, step, function (error, result) {
if (!error) {
codeMananger.event.trigger('changed', [code, address, result])
} else {
console.log(error)
}
})
}
module.exports = CodeManager

@ -1,5 +1,6 @@
'use strict'
var util = require('../helpers/util')
var AstWalker = require('./astWalker')
/**
* Decompress the source mapping given by solc-bin.js
@ -15,36 +16,7 @@ function SourceMappingDecoder () {
* @param {String} mapping - compressed source mapping given by solc-bin
* @return {Object} returns the decompressed source mapping for the given index {start, length, file, jump}
*/
SourceMappingDecoder.prototype.atIndex = function (index, mapping) {
var ret = {}
var map = mapping.split(';')
if (index >= map.length) {
index = map.length - 1
}
for (var k = index; k >= 0; k--) {
var current = map[k]
if (!current.length) {
continue
}
current = current.split(':')
if (ret.start === undefined && current[0] && current[0].length) {
ret.start = parseInt(current[0])
}
if (ret.length === undefined && current[1] && current[1].length) {
ret.length = parseInt(current[1])
}
if (ret.file === undefined && current[2] && current[2].length) {
ret.file = parseInt(current[2])
}
if (ret.jump === undefined && current[3] && current[3].length) {
ret.jump = current[3]
}
if (ret.start !== undefined && ret.length !== undefined && ret.file !== undefined && ret.jump !== undefined) {
break
}
}
return ret
}
SourceMappingDecoder.prototype.atIndex = atIndex
/**
* Decode the source mapping for the given compressed mapping
@ -103,6 +75,16 @@ SourceMappingDecoder.prototype.convertOffsetToLineColumn = function (sourceLocat
}
}
/**
* Retrieve the first @arg astNodeType that include the source map at arg instIndex
*
* @param {String} astNodeType - node type that include the source map instIndex
* @param {String} instIndex - instruction index used to retrieve the source map
* @param {String} sourceMap - source map given by the compilation result
* @param {Object} ast - ast given by the compilation result
*/
SourceMappingDecoder.prototype.findNodeAtInstructionIndex = findNodeAtInstructionIndex
function convertFromCharPosition (pos, lineBreakPositions) {
var line = util.findLowerBound(pos, lineBreakPositions)
if (lineBreakPositions[line] !== pos) {
@ -116,4 +98,76 @@ function convertFromCharPosition (pos, lineBreakPositions) {
}
}
function sourceLocationFromAstNode (astNode) {
if (astNode.src) {
var split = astNode.src.split(':')
return {
start: parseInt(split[0]),
length: parseInt(split[1]),
file: parseInt(split[2])
}
}
return null
}
function findNodeAtInstructionIndex (astNodeType, instIndex, sourceMap, ast) {
var sourceLocation = atIndex(instIndex, sourceMap)
return findNodeAtSourceLocation(astNodeType, sourceLocation, ast)
}
function findNodeAtSourceLocation (astNodeType, sourceLocation, ast) {
var astWalker = new AstWalker()
var callback = {}
var found = null
callback['*'] = function (node) {
var nodeLocation = sourceLocationFromAstNode(node)
if (!nodeLocation) {
return true
}
if (nodeLocation.start <= sourceLocation.start && nodeLocation.start + nodeLocation.length >= sourceLocation.start + sourceLocation.length) {
if (astNodeType === node.name) {
found = node
return false
} else {
return true
}
} else {
return false
}
}
astWalker.walk(ast.AST, callback)
return found
}
function atIndex (index, mapping) {
var ret = {}
var map = mapping.split(';')
if (index >= map.length) {
index = map.length - 1
}
for (var k = index; k >= 0; k--) {
var current = map[k]
if (!current.length) {
continue
}
current = current.split(':')
if (ret.start === undefined && current[0] && current[0].length) {
ret.start = parseInt(current[0])
}
if (ret.length === undefined && current[1] && current[1].length) {
ret.length = parseInt(current[1])
}
if (ret.file === undefined && current[2] && current[2].length) {
ret.file = parseInt(current[2])
}
if (ret.jump === undefined && current[3] && current[3].length) {
ret.jump = current[3]
}
if (ret.start !== undefined && ret.length !== undefined && ret.file !== undefined && ret.jump !== undefined) {
break
}
}
return ret
}
module.exports = SourceMappingDecoder

@ -0,0 +1,31 @@
'use strict'
var tape = require('tape')
var SourceMappingDecoder = require('../src/util/sourceMappingDecoder')
var compiler = require('solc')
tape('SourceMappingDecoder', function (t) {
t.test('SourceMappingDecoder.findNodeAtInstructionIndex', function (st) {
var output = compiler.compile(contracts, 0)
var sourceMappingDecoder = new SourceMappingDecoder()
var node = sourceMappingDecoder.findNodeAtInstructionIndex('FunctionDefinition', 2, output.contracts['test'].srcmapRuntime, output.sources[''])
st.equal(node, null)
node = sourceMappingDecoder.findNodeAtInstructionIndex('FunctionDefinition', 37, output.contracts['test'].srcmapRuntime, output.sources[''])
st.notEqual(node, null)
if (node) {
st.equal(node.attributes.name, 'f1')
}
st.end()
})
})
var contracts = `contract test {
function f1() returns (uint) {
uint t = 4;
return t;
}
function f2() {
}
}
`

@ -6,3 +6,4 @@ require('./util.js')
require('./astwalker.js')
require('./disassembler.js')
require('./eventManager.js')
require('./sourceMappingDecoder.js')

Loading…
Cancel
Save