This document presents an initial proposal of extra metadata that solc should emit for tools to be able to track all the local variables used in a transaction/call.

This document assumes basic knowledge about how local variables work in Solidity:

This document assumes variables in the stack do not move around in the stack once they are set in it. It is known that this can happen when optimizing, see the Supporting optimized builds section.

Metadata description

The minimal amount of information needed to identify a variable is:

For any variable there must be an instruction from which that variable can be accessed in the stack, and an instruction that marks the end of its scope. The later can be assumed to be the instruction that pops a variable from the stack, but it can also be provided for future-proofing.

constructorVariables: [
	{
	  id: 1, // AST-node Id
	  label: "myVariable",
	  type: "uint256",
	  location: "stack", //("stack"|"memory"|"storage"|"calldata")
	  startBytecodeOffset: 108,
		endBytecodeOffset: [145, 154],
	  stackOffset: 1
	}
],
runtimeVariables: [
	{
	  id: 2, // AST-node Id
	  label: "myRuntimeVariable",
	  type: "uint256",
	  location: "stack", //("stack"|"memory"|"storage"|"calldata")
	  startBytecodeOffset: 78,
		endBytecodeOffset: [99],
	  stackOffset: 0
	}
]

The reason why endBytecodeOffset is an array is because a function might have multiple return statements where a variable scope could end at any moment. This could be worked around by checking if the position in stack where the variable is set has been popped. However, this could end up being unreliable in certain cases, e.g. optimizations not popping the variable. It is useful for future proofing too. A mixture of both options could be used as well.

How to use it

This metadata can be used to track all the local variables created in a single contract execution. This includes function's variables and parameters, either inplace values or local pointers to memory, storage and calldata. Having the trace of the contract call, access to the storage, stack, memory and calldata during each execution step, and the compiler's output is enough.