Programs
Programs describe the high-level context at each point in EVM bytecode execution. They're the bridge between raw machine instructions and the source code developers wrote.
What programs contain
A program record corresponds to one block of executable bytecode—either a contract's runtime code (executed when called) or its creation code (executed during deployment).
Each program contains:
- Contract metadata: which contract this bytecode belongs to
- Instruction list: one entry per bytecode instruction, in order
Instructions carry context
The instruction list is the heart of a program. Each instruction record provides:
- Byte offset: where this instruction appears in the bytecode (equivalent to program counter on pre-EOF EVMs)
- Context information: high-level details valid after this instruction executes
Context information may include:
- Source ranges: which lines of source code this instruction relates to
- Variables: what variables are in scope and where their values live
- Control flow hints: whether this instruction is part of a function call, return, or other high-level operation
How debuggers use programs
When stepping through EVM execution, a debugger:
- Observes the current program counter
- Looks up the corresponding instruction in the program
- Uses the context to update its model of the high-level state
- Presents source code, variables, and call stacks to the developer
Each instruction's context acts as a state transition—a compile-time guarantee about what's true after that instruction runs.
Example: Simple instruction
{
"offset": 42,
"context": {
"code": {
"source": {
"id": 0,
"range": {
"start": { "line": 15, "column": 4 },
"end": { "line": 15, "column": 28 }
}
}
}
}
}
This says: "The instruction at byte 42 corresponds to line 15, columns 4-28 of source file 0."
Example: Instruction with variables
{
"offset": 100,
"context": {
"code": {
"source": { "id": 0, "range": { ... } }
},
"variables": [
{
"name": "balance",
"type": { "kind": "uint", "bits": 256 },
"pointer": {
"location": "stack",
"slot": 0
}
}
]
}
}
After instruction 100, the variable balance is in scope and its value is at
the top of the stack.
Context accumulates
Not every instruction needs complete context. The format supports incremental updates:
"pick": select from multiple possible contexts based on runtime conditions"gather": combine contexts (like nested scopes)"remark": add metadata without changing variable scope
This lets compilers emit compact debugging info that debuggers expand at runtime.
What's next
Instructions
How instruction records map bytecode to source.
Variables
Connecting identifiers to runtime locations.
Tracing execution
Using programs to inspect variables during execution.
Full specification
Complete JSON schemas for programs, instructions, and contexts.