Skip to content

Latest commit

 

History

History
227 lines (166 loc) · 10.9 KB

nep-19.mediawiki

File metadata and controls

227 lines (166 loc) · 10.9 KB

  NEP: 19
  Title: Debug Info Specification
  Author: Harry Pierson ([email protected])
  Type: Standard
  Status: Final
  Created: 2019-09-02

Table of Contents

Abstract

This NEP describes the debug information format used by the Neo Smart Contract Debugger. This information is generated by smart contract compilers such as NCCS and neo-boa.

Motivation

In order to provide a good developer experience, the debugger needs additional type information about parameters, variables and storage items that exists in the contract source code but is not needed by the NeoVM and is discarded during contract compilation. The debugger also needs to source map information in order to map binary addresses in compiled contracts to locations in source code.

Rationale

This format has been implemented by the Neo Smart Contract Debugger and multiple Neo smart contract compilers including NCCS, NEON, neo-boa, Neow3j and neo-go.

Debug Info Format Specification

Neo compilers SHOULD emit debug information as part of the compilation process along with the required compiled contract binary and contract manifest. Emitting debug information is optional, but the Neo Smart Contract Debugger will be limited to disassembly level debugging without it.

Debug info is stored in JSON format, described informally below and specified via the "neo-debug-info.schema.json" file. The debug info is stored in a file with the same base name as the contract binary with the extension ".debug.json". The debug info can be optionally compressed using standard Zip compression. When compressed, the debug info archive must have single ".debug.json" file and the archive itself must have an ".nefdbgnfo" extension.

Note, the format is defined in this specification using TypeScript for readability. There is no requirement that this format be implemented in TypeScript. The full specification of this format is specified in "neo-debug-info.schema.json"

The debug info has the following structure. Note, for space optimization, several string properties contain multiple pieces of information encoded as a string. Those encodings are indicated in comments in the code below.

  type TypeName = string; // format: ContractParamterType enum value

  type MemberName = string // format: "{namespace},{display-name}

  type Variable = string; // format: "{name},{TypeName}(,{slotIndex})?

  interface Method {
    id: string;
    name: MemberName; 
    range: string; // format: "{start-address}-{end-address}
    params?: Variable[]; 
    return?: TypeName;
    variables?: Variable[]; 
    "sequence-points"?: string[]; // format: "{address}[{document-index}]{start-line}:{start-column}-{end-line}:{end-column}"
  }

  interface Event {
    id: string;
    name: MemberName; 
    params?: Variable[]; 
  }

  interface DebugInformation {
    hash: string; // hex-encoded UInt160
    documents?: string[]; // absolute or relative file paths
    document-root?: string | null; // project root
    events?: Event[];
    methods?: Method[];
    "static-variables"?: Variable[]; 
  }

TypeName

TypeNames in Neo debug info are string encoded values from the ContractParameterType enum type

  • Any
  • Boolean
  • Integer
  • ByteArray
  • String
  • Hash160
  • Hash256
  • PublicKey
  • Signature
  • Array
  • Map
  • InteropInterface
  • Void
Generally, this type information is used to decode NeoVM types during debugging. For example, NeoVM has no native string type - strings are represented in NeoVM as a ByteString. The additional type information enables the debugger to treat the bytes in the NeoVM ByteString as a UTF-8 encoded string in order to decode the string for the developer.

Variable

Variable types are used to encode name and type information about NeoVM arguments, local variables and static fields. Additionally, a variable may include an optional slot index. This is useful for scenarios where the compiler may use slots for hidden variables not authored by the developer. If the slot index is not specified, the array index of the Variable type is used as the slot index. For a given variable array, ALL variables MUST include a slot index if ANY variables contain a slot index. Mixing variables with and and without an optional slot index in a single Variable array is NOT SUPPORTED. It is supported to have some Variable arrays include slot index information while other Variable arrays in the same debug info file do not.

Name, type and optional slot index are combined into a single comma separated string. A Variable without slot index has a single comma (i.e. "varName,varType") while a Variable with index has two commas (i.e. "varName,varType,1").

MemberName

MemberName types are used to store the name and optional namespace of a type member such as a method or event. MemberName namespace is optional, but the comma separator is not. For encoding members with no namespace, the MemberName string MUST start with a comma (i.e. ",SomeName").

Method

Method types have the following fields:

  • id: a unique string representing the method.
  • name: a MemberName with the method's name and optional namespace
  • range: the range of NeoVM bytecode addresses that is associated with this method. Range is encoded as a string with the start and end addresses as integers separated by a dash
  • params: a collection of Variable instances representing the NeoVM arguments associated with this method
  • return: the TypeName of the method's return value
  • variables: a collection of Variable instances representing the NeoVM local variables associated with this method
  • sequence-points: a collection of strings that encode a map of NeoVM bytecode addresses back to source code locations.
Note, params, return, variables and sequence-points are all optional. A Method object with no return property will default to having Void return type. A Method object with no params, variables or sequence-points properties will default to having an empty array of the collection in question.

A sequence point contains six integers encoded into a single string

  • address: This is an integer representing the location in the contract script of the sequence point.
  • document-index: This is an index into the documents array indicating the source code file containing the sequence point. documents array is described below.
  • start-line: This is the line in the source code file that is associated with the sequence point
  • start-column: This is the column of the line specified above in the source code file associated with the sequence point. Note, this value can be zero for languages that don't support mapping sequence points to segments within a line
  • end-line: for languages that support multi-line code expressions, this is the last line of the source code associated with the sequence point. For single-line expressions, this will be the same as start-line
  • end-column: for languages that support multi-line code expressions, this is column within end-line that marks the end of the sequence point code expression. Like start-column, it can be zero. Sequence points that have the same start/end line and zero for both start/end column will render the sequence point as the full line specified.
The six integers of a single sequence point are string encoded using this pattern:

  {address}[{document-index}]{start-line}:{start-column}-{end-line}:{end-column}

Event

Event types have the following fields:

  • id: a unique string representing the method.
  • name: a MemberName with the method's name and optional namespace
  • params: a collection of Variable instances representing the NeoVM arguments associated with this event
Note, like Method types, params is optional. An event object with no params property will default to an empty params array.

DebugInformation

Top level debug information has the following fields

hash

This property stores the UInt160 hash value of the contract's Script. Note, this is NOT the same as a deployed contract's script hash. The debugger uses this hash value to map deployed contracts to their debug information. The hash value is stored as a hex encoded string with an optional "0x" prefix.

documents

This property stores an array of file paths, used in sequence point data. These paths can be absolute or relative, pointing to the file paths of source files as they existed on the machine where the contract was compiled.

Neo Smart Contract Debugger has the ability to automatically discover differences in paths between compiling and debugging machine, plus supports manual source file mapping for cases where the mapping cannot be determined automatically.

If omitted, this property defaults to an empty array.

document-root

This property stores the root folder path for the contract source files. Releative paths in the documents array are treated as relative to the document-root path.

If omitted or null, all elements of the documents array are treated as absolute paths.

static-variables

This property stores an array of Variable types, representing the static fields associated with this contract. If omitted, this property defaults to an empty array.

methods

This property stores an array of Method types as described above. Each Method object represents a method in the contract. Both private and public methods from the contract should be represented in the methods array. If omitted, this property defaults to an empty array.

events

This property stores an array of Event types as described above. Each Event object represents a parameters of a contract notification that may be fired during contract execution. If omitted, this property defaults to an empty array.

Backwards Compatibility

Initial preview releases of the Neo Smart Contract Debugger for Neo Legacy used a more verbose format for debug info. That format was incompatible with the format described in this document, but never shipped a production release. Production releases of the Neo Legacy debugger use a slightly different version of the format described in this document.

The Neo N3 Debugger initially shipped during preview without the DebugInformation static-variables property or the slotIndex Variable value. These were added as optional fields before production release of the N3 Debugger.

Details regarding older versions of the debug info format is available in the original Design Note.

Implementation

NCCS: https://github.com/neo-project/neo-devpack-dotnet/blob/e9b00b7284819699a522c2d94ec22ef1d5e5be8a/src/Neo.Compiler.CSharp/CompilationContext.cs#L330-L362